home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / c / library / mslang / fs25 / fs1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-27  |  106.7 KB  |  3,614 lines

  1. /* FS1.C
  2.  * handle_dir functions
  3.  * MSC8 (VC++ 1.5)
  4.  * FS 2.5
  5.  * 270594
  6.  * Copyright (C) M. van Breemen, 1992-1994, All rights reserved.
  7.  */
  8.  
  9. #include "FS.H"
  10. #include "SPAWNO.H"
  11.  
  12. /* Prototypes */
  13. void make_today_string( char *daystring );
  14. int ed_turnover_datetime( void );
  15. int set_turnover_datetime( char *datetime );
  16. int date_interval_correct(unsigned long file_datetime, unsigned long turnover_datetime, int turnover_datetime_mode);
  17. int cdecl fs_systemo(const char *overlay_path, const char *command);
  18. int whereis(char *searchstring, int *current_page, int *filenumber );
  19. int find_name(char *fname, int *current_page, int *filenumber);
  20. void outtextm( char *string );
  21. int handle_dir( char *searchstring, char *selected , int safe_mode);
  22. char filename( int filenumber, int mode );
  23. void fileinfo( int filenumber );
  24. char *timestr( unsigned d, char *buf );
  25. char *datestr( unsigned d, char *buf );     
  26. unsigned int strtime( char *buf );
  27. unsigned int strdate( char *buf );
  28. unsigned long make_dt( unsigned d, unsigned t);
  29. void set_cursor( int filenumber );
  30. void clear_remaining( int filenumber );
  31. int extract_directory( char *searchstring );
  32. void put_parent_on_top( int order_type );
  33. void make_parent_two_dots( void );
  34. void show_dir_page( int page );
  35. void kader( void );
  36. void alert( void );
  37. void helpscreen( void );
  38. void aboutscreen( void );
  39. void show_error( char *message );
  40. void show_message( char *message );
  41. void wait_sec( int milliseconds );
  42. int rename_file( int filenumber);
  43. int rename_volume_label( int filenumber);
  44. void _far hhandler( unsigned deverr, unsigned doserr, unsigned _far *hdr );
  45. int _bios_str( char *p );
  46. void clear_left_button_queue( void );
  47. void clear_right_button_queue( void );
  48. int read_left_button_queue( int *row, int *col );
  49. int read_right_button_queue( int *row, int *col );
  50. void init_mouse( void );
  51. void hide_mouse( void );
  52. void show_mouse( void );
  53. int mouse_button_pressed( void );
  54. void perform_repaint(int current_page, int filenumber);
  55. void c_pgup( int *current_page, int *filenumber);
  56. void c_pgdn( int *current_page, int *filenumber);
  57. void find_first(char chr, int *currentpage, int *filenumber);
  58. void c_home( int *current_page, int *filenumber);
  59. void c_end( int *current_page, int *filenumber);
  60. void c_cup( int *current_page, int *filenumber);
  61. void c_cdn( int *current_page, int *filenumber);
  62. void c_cri( int *current_page, int *filenumber);
  63. void c_cle( int *current_page, int *filenumber);
  64. int _cdecl cmpgle( const void *elem1, const void *elem2 );
  65. unsigned int n_kbhit( void );
  66. int show_file(char *filename);
  67. int old_show_file(char *filename);
  68. int getkey(void);
  69. void changecursor(int insmode);
  70. void setcursor(unsigned int shape);
  71. unsigned int getshift(void);
  72. int editstring(int row, int col, char *s, char *legal_illegal, int legalmode, int maxlength);
  73. int edit(char *title, char *string, int length , char *legal_illegal, int legalmode);
  74. int copy_file( int filenumber);
  75. int make_directory( void );
  76. int ed_attributes( int filenumber);
  77. int ed_datetime( int filenumber);
  78. int copy( char *oldname, char *newname );
  79. char __near *saveScrn(void);
  80. char __near *restScrn(char __near *saveArea);
  81. void show_path( void );
  82. int valid_filename( char *newname);
  83. int freespace( char *linebuf );
  84. int getdiskfree( int newdrive, long *freebytes );
  85. void working( int mode );
  86. void shadebox( short r1, short c1, short r2, short c2 );
  87. void shadechar( int row, int col );
  88. char *set_working_drive_and_dir( char *full_filename );
  89. int find_in_file( char *filename , char *string, int ignore_case);
  90. void do_dir(char *path);
  91. void find_parent( int *current_page, int *filenumber, char *searchstring);
  92. int getdrv(void);
  93. int chdrv(int drive);
  94. int drvalid(int drive);
  95. char *FilGetVolid( unsigned char Drive );
  96. int FilSetVolid( unsigned char Drive, char *Volid );
  97. int FilDelVolid( unsigned char Drive );
  98. void ScrPutS(char *String, unsigned char Attr,
  99.          unsigned char Row, unsigned char Col);
  100. int ask_drive_number(char *message);
  101. void construct_search_path( char *linebuf );
  102. int floptest(int drv);
  103. char *getpath( int drive, char *buffer, int maxlen );
  104. char __near *show_string(char *string, int bg_color, int text_color);
  105. void paint_box(char *string, int vis_width, int vis_height);
  106. void restrict_mouse_topline( void );
  107. void default_mouse_rectangle( void );
  108.  
  109. /* global variables */
  110. char turnover_datetime_string[23]={"\0"};
  111. unsigned long turnover_datetime;
  112. int turnover_datetime_mode=SINCE;
  113.  
  114. char processor[_MAX_PATH]={"\0"};
  115.  
  116. unsigned short int checkpoint1[3]= { 0xFEFF, 0xFCFD, 0xFAFB }; /* Backword FFFEFDFCFBFA */
  117. short int screen_bg_color        = BLUE;
  118. short int file_color             = WHITE;
  119. short int hidden_file_color      = BRIGHTWHITE;
  120. short int directory_color        = YELLOW;
  121. short int hidden_directory_color = LIGHTGREEN;
  122. short int volume_label_color     = CYAN;             /* 11 bytes color info and fsswitch */
  123. short int cursor_bg_color        = RED;
  124. short int info_bg_color          = GREEN;
  125. short int info_text_color        = BRIGHTWHITE;
  126. short int error_bg_color         = RED;
  127. short int error_text_color       = WHITE;
  128. short int fsswitch = (short int) '/';    /* parameter switch character for FS */   
  129. unsigned short int checkpoint2[3]= { 0xFBFA, 0xFDFC, 0xFFFE }; /* Backword FAFBFCFDFEFF */
  130.  
  131. /* for monochrome systems */
  132. short int cursor_file_color;
  133. short int cursor_directory_color;
  134. short int cursor_hidden_file_color;
  135. short int cursor_hidden_directory_color;
  136. short int cursor_volume_label_color;
  137.  
  138. static char searchstring[13]={"\0"};
  139.  
  140. char *swap_dir;
  141. int allow_swap;
  142. int swap_types;
  143. int order_by;                                                  /* NONE, NAME, DATE or SIZE */
  144. int order_type;                                                /* ASCENDING or DESCENDING */
  145.  
  146. static struct {                            /* FCB for volume label functions */
  147.           unsigned char Extcode;
  148.           char Res1[5];
  149.           unsigned char Code;
  150.           unsigned char OldDrive;
  151.           char OldName[11];
  152.           char Res2[5];
  153.           char NewName[11];
  154.           char Res3[9];
  155.           } DirFcb = {0xFF,"",0x10,0,"","","",""},
  156.         VolFcb = {0xFF,"",0x08,0,"???????????","","",""};
  157.  
  158. static struct {                            /* DTA for volume label functions */
  159.           char Res1[8];      /* reserved */
  160.           char OldVolid[11]; /* filled in by DOS */
  161.           char Res2[5];      /* reserved */
  162.           char NewVolid[11]; /* used by FilSetVolid */
  163.           char Res3[9];      /* reserved */
  164.           } Dta;
  165.  
  166. int number_of_files;    /* number of files found */
  167.  
  168. typedef struct find_t_small {
  169.                 char name [13];
  170.                 char attrib;
  171.                 unsigned long datetime_or_size;
  172.                 /* char filler[14]; */
  173.                 } FIND_T_SMALL;
  174.  
  175. FIND_T_SMALL __huge *find;       /* pointer to the file info structures */
  176. /* The size of find[] is limited to 128K due to _halloc limitations. */
  177. /* Extend the structure to 32 bytes (power of 2) to increase the capacity */
  178. /* The penalty is inefficient use of memory (14 bytes filler per structure) */
  179.  
  180. int mouse_present;      /* boolean is there a mouse ? */
  181. int mouse_row=0;        /* mouse position, NOT screen rows and columns */
  182. int mouse_col=0;
  183. int max_files;           /* maximal number of accessible files per directory or root, defaults to 912 */
  184. int dos_error;           /* set by error handler */
  185. int dos_retries;         /* set by error handler */
  186. int dos_error_auto_fail=FALSE;  /* read by error handler */
  187. int allow_abort_on_error=FALSE;
  188. int setting_factory_defaults=FALSE;
  189.       
  190.       
  191.       
  192.       
  193.       
  194. /* volume label functions taken from 'Systems Programming in Microsoft C, Michael J. Young */
  195.  
  196. char *FilGetVolid( unsigned char Drive )
  197. {
  198.     int ErrorCode;
  199.     union REGS Reg;
  200.     
  201.     dos_error_auto_fail=TRUE;
  202.     Reg.x.dx = (unsigned int) &Dta;
  203.     Reg.h.ah = 0x1A;
  204.     int86(0x21, &Reg, &Reg);
  205.     VolFcb.OldDrive = Drive;
  206.     Reg.x.dx = (unsigned int) &VolFcb;
  207.     Reg.h.ah = 0x11;
  208.     int86(0x21, &Reg, &Reg);
  209.     dos_error_auto_fail=FALSE;
  210.     
  211.     ErrorCode = Reg.h.al;
  212.     if (ErrorCode == 0) return (Dta.OldVolid);
  213.     else return (NULL);
  214. }
  215.  
  216. int FilSetVolid( unsigned char Drive, char *Volid )
  217. {
  218.     register int i;
  219.     int ErrorCode;
  220.     union REGS Reg;
  221.     if (FilGetVolid(Drive)==NULL)
  222.     {
  223.     dos_error_auto_fail=TRUE;
  224.     for (i=0;i<11;++i)
  225.         if (*Volid=='\0') VolFcb.OldName[i]= ' ';
  226.         else VolFcb.OldName[i]= *Volid++;
  227.     Reg.x.dx=(unsigned int) &VolFcb;
  228.     Reg.h.ah=0x16;
  229.     int86(0x21, &Reg, &Reg);
  230.     dos_error_auto_fail=FALSE;
  231.     
  232.     ErrorCode=Reg.h.al;
  233.     if (ErrorCode==0) return (NOERROR);
  234.     else return (NOCREAT);
  235.     }
  236.     else
  237.     {
  238.     dos_error_auto_fail=TRUE;
  239.     for (i=0;i<11;++i)
  240.         if (*Volid=='\0') Dta.NewVolid[i]= ' ';
  241.         else Dta.NewVolid[i]= *Volid++;
  242.     Reg.x.dx=(unsigned int) &Dta;
  243.     Reg.h.ah=0x17;
  244.     int86(0x21, &Reg, &Reg);
  245.     
  246.     dos_error_auto_fail=FALSE;
  247.     ErrorCode=Reg.h.al;
  248.     if (ErrorCode==0) return (NOERROR);
  249.     else return (NOREN);
  250.     }
  251. }
  252.  
  253. int FilDelVolid( unsigned char Drive )
  254. {
  255.     int ErrorCode;
  256.     union REGS Reg;
  257.  
  258.     if (FilGetVolid ( Drive )==NULL)
  259.     {
  260.     return (NOVOL);
  261.     }
  262.     else
  263.     {
  264.     dos_error_auto_fail=TRUE;
  265.     Reg.x.dx=(unsigned int) &Dta;
  266.     Reg.h.ah=0x13;
  267.     int86(0x21, &Reg,&Reg);
  268.  
  269.     dos_error_auto_fail=FALSE;
  270.     ErrorCode=Reg.h.al;
  271.     if (ErrorCode==0) return (NOERROR);
  272.     else return (NODEL);
  273.     }
  274. }
  275.  
  276. /*---------------------------------------------------------------------------*/
  277. /*   FF Routines taken from FFF 3.4.5, a public domain program to search files
  278.  *      Author: Don A. Williams                                                                                  *
  279.  *              CompuServ -                                                                                      *
  280.  *              Genie     - DON-WILL                                                                             
  281.  *   These routines are customized
  282. */
  283.  
  284.  
  285. #define U_ESC    1
  286. #define U_SELECT 2
  287. #define U_GOTO 3
  288.  
  289. #define FIND_FIRST(Name,Block,Attrib) _dos_findfirst(Name, Attrib, Block);
  290. #define FIND_NEXT(Block) _dos_findnext(Block);
  291. #define DIR_ENTRY find_t        /* Name of the directory entry structure        */
  292. #define D_ATTRIB attrib         /* Attribute field in directory entry           */
  293. #define D_NAME name             /* File name field in directory entry           */
  294.  
  295.  
  296. typedef struct QueEntry {
  297.               struct QueEntry *Next;
  298.               char  *Body;
  299.             } QUE_ENTRY;
  300.  
  301. typedef struct QueDef {
  302.             QUE_ENTRY *Head, *Current;
  303.             int        Count;
  304.               } QUE_DEF;
  305.  
  306. /* Function prototypes    */
  307.  
  308. int             fff( char *fpattern, char *sstring, int ignore_case);
  309. void            InitQueue (QUE_DEF *Q);
  310. QUE_ENTRY       *Enque (QUE_DEF *Q, void *Body);
  311. int             WalkTree (QUE_DEF * Q, char *sstring , int ignore_case);
  312. int             SearchQ (char *Str);
  313. int             Match (char *Str, char *Pat);
  314. static int      I_Match (char *Str, char *Pat);
  315. static int      S_Match (char *S, char *P, int Anchor);
  316.  
  317. /*----------------------------------------------------------------------*/
  318.  
  319. QUE_DEF         PatQue;
  320. char            T_Path[_MAX_PATH];                    /* Temporary directory path to search   */
  321. char            V_Path[_MAX_PATH];                    /* Selected file */
  322.  
  323. /**************************************************************************
  324.  Find and put cursor on file with matching name
  325. */
  326. int find_name(char *fname, int *current_page, int *filenumber)
  327. {
  328.      register int counter;
  329.      int result=FAILURE;
  330.      if (!number_of_files) return (result);
  331.      for (counter=1;counter<=number_of_files;counter++)
  332.        if (!strcmp(find[counter].name,fname))
  333.        {
  334.        result=SUCCESS;
  335.        break;
  336.        }
  337.      if (result==SUCCESS)
  338.      {
  339.      *filenumber=counter;
  340.      *current_page=((counter%114) ? counter/114 : counter/114 - 1);
  341.      }
  342.      return (result);
  343. }
  344.  
  345. /*************************************************************************
  346.  hide mouse, _outtext, show_mouse
  347. */
  348. void outtextm( char *string )
  349. {
  350.     hide_mouse();
  351.     _outtext(string);
  352.     show_mouse();
  353. }
  354.  
  355. /*************************************************************************
  356.   Returns F for normal file, D for directory, V for volume label, H for hidden file.
  357.   Displays Filename if mode != NOREPAINT
  358. */
  359. char filename( int filenumber, int mode )
  360. {
  361.     char type, namebuf[14];
  362.     static struct videoconfig vc={0,0,0,0,0,0,0,0,0,0,0};
  363.  
  364.     if (!vc.numcolors) _getvideoconfig( &vc ); /* initialize on first call */
  365.  
  366.     if (vc.mode==_TEXTMONO)
  367.     sprintf( namebuf, "%c%-12s",
  368.          (find[filenumber].attrib & _A_HIDDEN) ? '' : ' ',
  369.          find[filenumber].name);
  370.     else sprintf( namebuf, "%-12s ",find[filenumber].name);
  371.  
  372.     if( find[filenumber].attrib & _A_SUBDIR )      type='D';  /* directory */
  373.     else if( find[filenumber].attrib & _A_VOLID )  type='V';  /* volume label */
  374.      else type='F';                                       /* normal file */
  375.  
  376.     switch (mode)
  377.     {
  378.     case NOREPAINT: break;
  379.     case CURSOR: set_cursor( filenumber );
  380.          switch (type)
  381.          {
  382.             case 'D': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) cursor_hidden_directory_color );
  383.                   else _settextcolor( (short) cursor_directory_color );
  384.                   break;
  385.             case 'V': _settextcolor( (short) cursor_volume_label_color );
  386.                   break;
  387.             case 'F': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) cursor_hidden_file_color );
  388.                   else _settextcolor( (short) cursor_file_color );
  389.                   break;
  390.          }    
  391.          if (number_of_files) _setbkcolor( (long) cursor_bg_color );
  392.          outtextm( namebuf );
  393.          _setbkcolor( (long) screen_bg_color );
  394.          break;
  395.     case NORMAL: set_cursor( filenumber );
  396.          switch (type)
  397.          {
  398.             case 'D': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) hidden_directory_color );
  399.                   else _settextcolor( (short) directory_color );
  400.                   break;
  401.             case 'V': _settextcolor( (short) volume_label_color );
  402.                   break;
  403.             case 'F': if (find[filenumber].attrib & _A_HIDDEN) _settextcolor( (short) hidden_file_color );
  404.                   else _settextcolor( (short) file_color );
  405.                   break;
  406.          }
  407.          _setbkcolor( (long) screen_bg_color );
  408.          outtextm( namebuf );
  409.          break;
  410.     }
  411.     return (type);
  412. }
  413.  
  414.  
  415. /***************************************************************************
  416.  Displays information about a file.
  417. */
  418. void fileinfo( int filenumber )
  419. {
  420.     char timebuf[9], datebuf[12], attrbuf[5], namebuf[13], sizebuf[9], type;
  421.     struct find_t pfind;
  422.     short x,y,c;
  423.     char b[8*29+10];                    /* Buffer for string */
  424.     char __near *savedscreen;
  425.     int key=0;
  426.     unsigned result;
  427.  
  428.     /* get full file information */
  429.     working(TRUE);
  430.     dos_error_auto_fail=TRUE;
  431.     if (!strcmp(find[filenumber].name,"..")) result=_dos_findfirst( ".", 0xffff, &pfind );
  432.     else result=_dos_findfirst( find[filenumber].name, 0xffff, &pfind );
  433.     working(FALSE);
  434.     dos_error_auto_fail=FALSE;
  435.     if (result) /* not succeeded, get out */
  436.     {
  437.        show_error("Cannot get the information for this file ");
  438.        return;
  439.     }
  440.     savedscreen=saveScrn();
  441.  
  442.     y = ((25 -  8) / 2) + 1;     /* 8 lines, add 1 to center in FS window */
  443.     x = ((80 - 28) / 2);         /* 28 visible characters per line */
  444.  
  445.     datestr( pfind.wr_date, datebuf );
  446.     timestr( pfind.wr_time, timebuf );
  447.  
  448.     sprintf( attrbuf, "%c%c%c%c",
  449.         (pfind.attrib & _A_RDONLY) ? 'R' : '_',
  450.         (pfind.attrib & _A_HIDDEN) ? 'H' : '_',
  451.         (pfind.attrib & _A_SYSTEM) ? 'S' : '_',
  452.         (pfind.attrib & _A_ARCH)     ? 'A' : '_' );
  453.  
  454.     sprintf( sizebuf, "%ld", pfind.size);
  455.  
  456.     sprintf( namebuf, "%-12s", pfind.name);
  457.  
  458.     if( pfind.attrib & _A_SUBDIR )       type='D';  /* directory */
  459.     else if( pfind.attrib & _A_VOLID )   type='V';  /* volume label */
  460.      else type='F';                             /* normal file */
  461.  
  462.     _settextcolor( (short) info_text_color );
  463.     _setbkcolor( (long) info_bg_color );
  464.     /* Use text window to place output in middle of screen */
  465.     /* The window is 1 position larger than the output string. */
  466.     _settextwindow( y, x, y + 8, x + 28 );
  467.     shadebox(    y, x, y + 8 - 1 , x + 28 - 1 );
  468.  
  469.     /* Write all information to a string, then output string. */
  470.     c  = sprintf( b    , "╔══════════════════════════╗\n");
  471.     c += sprintf( b + c, "║ Filename  : %-12s ║\n",namebuf);
  472.     c += sprintf( b + c, "║ Size      : %-12s ║\n",sizebuf);
  473.     c += sprintf( b + c, "║ Date      : %-12s ║\n",datebuf);
  474.     c += sprintf( b + c, "║ Time      : %-12s ║\n",timebuf);
  475.     c += sprintf( b + c, "║ Attributes: %-12s ║\n",attrbuf);
  476.     c += sprintf( b + c, "║ Type      : ");
  477.     switch (type)
  478.     {
  479.     case 'F': c += sprintf( b + c, "%-12s ║\n","File");
  480.           break;
  481.     case 'D': c += sprintf( b + c, "%-12s ║\n","Directory");
  482.           break;
  483.     case 'V': c += sprintf( b + c, "%-12s ║\n","Volume label");
  484.           break;
  485.     }
  486.     c += sprintf( b + c, "╚══════════════════════════╝\n");
  487.     outtextm( b );
  488.     while (!(key=n_kbhit()) && !mouse_button_pressed()) /* wait */ restrict_mouse_topline();
  489.     _settextwindow( 3, 1, 23, 80 );
  490.     _setbkcolor( (long) screen_bg_color );
  491.     savedscreen=restScrn(savedscreen);
  492.     if ((key & 0x00FF)==ESC) getkey();  /* trash ESC */
  493. }
  494.  
  495. /***************************************************************************
  496.  * Takes unsigned time in the format:             fedcba9876543210
  497.  * s=2 sec incr, m=0-59, h=23                       hhhhhmmmmmmsssss
  498.  * Changes to a 8-byte string:                      hh:mm:ss
  499.  */
  500. char *timestr( unsigned t, char *buf )
  501. {
  502.     int h = (t >> 11) & 0x1f, m = (t >> 5) & 0x3f, s= t & 0x1f;
  503.  
  504.     sprintf( buf, "%2.2d:%02.2d:%02.2d", h, m, s*2 );   return buf;
  505. }
  506.  
  507. /**************************************************************************
  508.  * Takes unsigned date in the format:               fedcba9876543210
  509.  * d=1-31, m=1-12, y=0-119 (1980-2099)              yyyyyyymmmmddddd
  510.  * Changes to a 11-byte string:                     DD-MON-YYYY
  511.  */
  512. char *datestr( unsigned d, char *buf )
  513. {
  514.     char *month[]={"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
  515.     int day = d & 0x1f, m = (d >> 5) & 0x0f, y = ((d >> 9) & 0x7f) + 1980;
  516.  
  517.     sprintf( buf, "%02d-%s-%d", day, month[m-1], y);
  518.     return buf;
  519. }
  520.  
  521. /***************************************************************************
  522.  * Takes time in a 8-byte string:                      hh:mm:ss
  523.  * Changes to unsigned time in the format:             fedcba9876543210
  524.  * s=0-29 (2 sec incr), m=0-59, h=0-23                 hhhhhmmmmmmsssss
  525.  */
  526. unsigned int strtime( char *buf )
  527. {   
  528.     unsigned int t;
  529.     int hour;
  530.     int min;
  531.     int sec;
  532.     int corrected=FALSE;
  533.     
  534.     sec = atoi(buf+6); 
  535.     if (sec<0)
  536.     {
  537.         sec=0;
  538.         corrected=TRUE;
  539.     }    
  540.     if (sec>59)
  541.     {
  542.         sec=59;
  543.         corrected=TRUE;
  544.     }    
  545.     t = sec / 2;
  546.     
  547.     buf[5] = '\0';
  548.     min=atoi(buf+3);
  549.     if (min<0)
  550.     {
  551.         min=0;
  552.         corrected=TRUE;
  553.     }    
  554.     if (min>59)
  555.     {
  556.         min=59;
  557.         corrected=TRUE;
  558.     }    
  559.     t += (min << 5);
  560.     
  561.     buf[2] = '\0';
  562.     hour=atoi(buf);
  563.     if (hour<0)
  564.     {
  565.         hour=0;
  566.         corrected=TRUE;
  567.     }    
  568.     if (hour>23)
  569.     {
  570.         hour=23;
  571.         corrected=TRUE;
  572.     }    
  573.     t += (hour << 11);  
  574.     
  575.     if (corrected) show_error("Limited time between 00:00:00 and 23:59:59");
  576.     
  577.     return t;
  578. }
  579.  
  580.  
  581. /**************************************************************************
  582.  * Takes date in a 11-byte string:                     DD-MON-YYYY
  583.  * Changes to unsigned date in the format:             fedcba9876543210
  584.  * d=1-31, m=1-12, y=0-119 (1980-2099)                 yyyyyyymmmmddddd
  585.  */
  586. unsigned int strdate( char *buf )
  587. {   
  588.     char *month[]={"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
  589.     int mnth=0;
  590.     unsigned int date;
  591.     int day;
  592.     int year;
  593.     int corrected=FALSE;
  594.                  
  595.     strupr(buf);
  596.                  
  597.     year = atoi(buf+7)-1980;
  598.     if (year<0) 
  599.     {
  600.         year=0;          /* limit to valid year */
  601.         corrected=TRUE; 
  602.     }    
  603.     if (year>119)
  604.     {
  605.         year=119;
  606.         corrected=TRUE; 
  607.     }    
  608.     date = (year << 9);
  609.     
  610.     buf[6] = '\0';
  611.     while (strcmp(buf+3,month[mnth]) && mnth<=11) mnth++;
  612.     if (mnth>11)
  613.     {
  614.         mnth=0;         /* limit to valid month */
  615.         corrected=TRUE; 
  616.     }    
  617.     date += ((++mnth) << 5);
  618.        
  619.     buf[2] = '\0';
  620.     day = atoi(buf);       
  621.     if (day<1)
  622.     {
  623.         day=1;            /* limit to valid day */
  624.         corrected=TRUE; 
  625.     }    
  626.     if (day>31)
  627.     {
  628.         day=31;
  629.         corrected=TRUE; 
  630.     }    
  631.     date += day;
  632.        
  633.     if (corrected) show_error("Limited date between 01-JAN-1980 and 31-DEC-2099");
  634.        
  635.     return date;  
  636. }
  637.  
  638. /***************************************************************************
  639.  * Calculate page, line, column from filenumber and sets cursor position
  640.  * Displays page number if this is changed
  641.  * pagelayout: 6 columns of 19 files per page, 114 files per page,
  642.  *             starting at window line 1, column width 13 (position 1,14,27...)
  643.  * filenumber= 1,2,...
  644.  * page      = 0,1,...
  645.  * line      = 2,3,...,21
  646.  * column    = 2,15,28,41,54,67
  647.  */
  648. void set_cursor( int filenumber )
  649. {
  650.     int line, column, relfilenumber, old_page, old_max_page;
  651.     char linebuf[10];
  652.     static int page=-1;
  653.     static int max_page=-1;
  654.     old_page=page;
  655.     old_max_page=max_page;
  656.     max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  657.     line=((filenumber%19) ? filenumber%19 : 19) + 1;
  658.     page=((filenumber%114) ? filenumber/114 : filenumber/114 - 1);
  659.     relfilenumber=(filenumber - page*114);
  660.     column=((relfilenumber%19) ? relfilenumber/19 : relfilenumber/19 - 1) * 13 + 2;
  661.     if (old_page!=page || old_max_page!=max_page)
  662.     {
  663.     sprintf(linebuf,"%d/%d ══",page+1,max_page+1);
  664.     _settextposition( 1, 72 );
  665.     _settextcolor( (short) file_color );
  666.     _setbkcolor( (long) screen_bg_color );
  667.     outtextm(linebuf);
  668.     }
  669.     _settextposition( line, column );
  670. }
  671.  
  672.  
  673. /**************************************************************************
  674.   Clear remaining directory page by displaying blank names, starting with
  675.   filenumber+1
  676.  */
  677. void clear_remaining( int filenumber )
  678. {
  679.     register int line, column, relfilenumber;
  680.     int page;
  681.  
  682.     hide_mouse();
  683.     page=((filenumber%114) ? filenumber/114 : filenumber/114 - 1);
  684.     relfilenumber=(filenumber - page*114);
  685.     _setbkcolor( (long) screen_bg_color );
  686.     _settextcolor( (short) file_color );
  687.     while (relfilenumber < 114 )
  688.     {
  689.     filenumber++;
  690.     relfilenumber++;
  691.     line=((filenumber%19) ? filenumber%19 : 19) + 1;
  692.     column=((relfilenumber%19) ? relfilenumber/19 : relfilenumber/19 - 1) * 13 + 2;
  693.     _settextposition( line, column );
  694.     outtextm( "             " );
  695.     }
  696.     show_mouse();
  697. }
  698.  
  699. /***************************************************************************
  700.  * Compares e1 and e2 and returns greater than (>0), less than (<0), or equal to (0).
  701.  * This function is called by qsort.
  702.  */
  703.  
  704. int _cdecl cmpgle( const void *elem1, const void *elem2 )
  705. {
  706.     const struct find_t_small *e1, *e2;
  707.     e1=elem1;
  708.     e2=elem2;
  709.     if (order_type==DESCENDING)
  710.     { 
  711.        switch(order_by)
  712.        {
  713.       case SIZE:
  714.       case DATE: if (e1->datetime_or_size < e2->datetime_or_size) return (1);
  715.              if (e1->datetime_or_size > e2->datetime_or_size) return (-1);
  716.              if (e1->datetime_or_size == e2->datetime_or_size) return (0);
  717.              break;
  718.       case NAME: return (strcmp(e2->name,e1->name));
  719.              break;
  720.        }
  721.     }
  722.     else
  723.     {
  724.        switch(order_by)
  725.        {
  726.       case SIZE:
  727.       case DATE: if (e1->datetime_or_size < e2->datetime_or_size) return (-1);
  728.              if (e1->datetime_or_size > e2->datetime_or_size) return (1);
  729.              if (e1->datetime_or_size == e2->datetime_or_size) return (0);
  730.              break;
  731.       case NAME: return (strcmp(e1->name,e2->name));
  732.              break;
  733.        }
  734.     }
  735. }
  736.  
  737. /***************************************************************************
  738.  Fills find structure and sets number_of_files global. Filters files with
  739.  searchstring mask. Skips "." directory and volume label. Sorts find structure
  740. */
  741. int extract_directory( char *searchstring )
  742. {
  743.     struct find_t findtemp;
  744.     char type;
  745.     int key;
  746.  
  747.     number_of_files=0;
  748.     working(TRUE);
  749.     /* Find first matching file, then find additional matches. */
  750.     dos_error_auto_fail=TRUE;
  751.     if( !_dos_findfirst( "*.*\0", _A_ARCH | _A_HIDDEN | _A_NORMAL | _A_RDONLY |
  752.                   _A_SUBDIR | _A_SYSTEM | _A_VOLID, &findtemp ) )
  753.     {
  754.        if( findtemp.attrib & _A_SUBDIR ) type='D';      /* directory */
  755.        else if( findtemp.attrib & _A_VOLID ) type='V'; /* volume label */
  756.         else type='F'; /* normal file (and hidden file) */
  757.        if (findtemp.name[0]=='.' && findtemp.name[1]=='\0' && type== 'D') type='N'; /* null dir */
  758.        if (type=='F' || type=='D' || type=='V')
  759.        {
  760.      strcpy(find[++number_of_files].name,findtemp.name);
  761.      find[number_of_files].attrib=findtemp.attrib;
  762.      if (order_by==SIZE) find[number_of_files].datetime_or_size=(unsigned long) findtemp.size;
  763.      else find[number_of_files].datetime_or_size=make_dt(findtemp.wr_date,findtemp.wr_time);
  764.        }
  765.        if (type=='F' && strlen(searchstring) && !Match(findtemp.name,searchstring)) number_of_files--;
  766.  
  767.        while( !_dos_findnext( &findtemp ) && (number_of_files < max_files ))
  768.        {
  769.      if( findtemp.attrib & _A_SUBDIR ) type='D';    /* directory */
  770.      else if( findtemp.attrib & _A_VOLID ) type='V'; /* volume label */
  771.           else type='F'; /* normal file */
  772.      if (findtemp.name[0]=='.' && findtemp.name[1]=='\0' && type== 'D') type='N'; /* null dir */
  773.      if (type=='F' || type=='D' || type=='V')
  774.      {
  775.        strcpy(find[++number_of_files].name,findtemp.name);
  776.        find[number_of_files].attrib=findtemp.attrib;
  777.        if (order_by==SIZE) find[number_of_files].datetime_or_size=(unsigned long) findtemp.size;
  778.        else find[number_of_files].datetime_or_size=make_dt(findtemp.wr_date,findtemp.wr_time);
  779.      }
  780.      /* do we really want this file? */
  781.      if (type=='F')
  782.      {              
  783.          /* does it match the mask ? */
  784.          if (strlen(searchstring) && !Match(findtemp.name,searchstring))
  785.             number_of_files--; 
  786.          /* does it match the date and time ? */   
  787.          else if (!date_interval_correct(make_dt(findtemp.wr_date,findtemp.wr_time),turnover_datetime, turnover_datetime_mode))
  788.                  number_of_files--;
  789.      }      
  790.  
  791.          /* user cancels find operation */
  792.      if (n_kbhit()) 
  793.      {   
  794.          key=getkey();
  795.              if ((key & 0x00FF)==ESC) 
  796.              {    
  797.                  getkey();  /* trash ESC */ 
  798.                  show_message( "Aborted by user, not all files visible" );
  799.                  break;
  800.              } 
  801.          }   
  802.      
  803.        }
  804.     }
  805.     working(FALSE);
  806.     dos_error_auto_fail=FALSE;
  807.     if (!number_of_files)
  808.     {
  809.     show_message( "No files found" );
  810.     find[1].attrib='\0';
  811.     find[1].name[0]='\0';
  812.     find[1].datetime_or_size=0L;
  813.     return FAILURE;
  814.     }
  815.  
  816.     if (order_by != NONE)
  817.     {
  818.     working(TRUE);
  819.     put_parent_on_top(order_type);
  820.     qsort( (void *) (&(find[1])), (size_t) number_of_files,
  821.            (size_t) sizeof(FIND_T_SMALL), cmpgle);
  822.     make_parent_two_dots();
  823.     working(FALSE);
  824.     }
  825.  
  826.     return SUCCESS;
  827. }
  828.  
  829. void put_parent_on_top( int order_type )
  830. {
  831.     register int counter;
  832.  
  833.     for (counter=1;counter<number_of_files;counter++)
  834.     {
  835.     if (!strcmp(find[counter].name,".."))     /* force .. directory on top */
  836.     {
  837.        if (order_type==ASCENDING)
  838.        {
  839.            find[counter].datetime_or_size=0L;
  840.            find[counter].name[0]='\0';
  841.            find[counter].name[1]='\0';
  842.        }
  843.        else
  844.        {
  845.            find[counter].datetime_or_size=0xFFFFFFFFL;
  846.            find[counter].name[0]=(unsigned char) 0xFF;
  847.            find[counter].name[1]='\0';
  848.  
  849.        }
  850.        break;
  851.     }
  852.     }
  853. }
  854.  
  855. void make_parent_two_dots( void )
  856. {
  857.     register int counter;
  858.  
  859.     for (counter=1;counter<number_of_files;counter++)
  860.     {
  861.     if (find[counter].name[1]=='\0' &&
  862.         (find[counter].name[0]=='\0' || find[counter].name[0]==(unsigned char) 0xFF))
  863.     {                 /* restore parent to .. */
  864.        strcpy(find[counter].name,"..");
  865.        break;
  866.     }
  867.     }
  868.  
  869. }
  870.  
  871. /* Construct yymmddhhmmss number to enable sort on file date & time */
  872. unsigned long make_dt( unsigned d, unsigned t)
  873. {
  874.     unsigned long dt;
  875.  
  876.     dt= ( ((unsigned long) d) << 16) + ((unsigned long) t);
  877.     return dt;
  878. }
  879.  
  880. /****************************************************************************
  881.  Display the filenames of one page
  882. */
  883. void show_dir_page( int page )
  884. {
  885.     register int filenumber;
  886.     for (filenumber=1 + page*114; filenumber<=(114 + page*114) && filenumber<=number_of_files; filenumber++)
  887.     {
  888.     filename( filenumber, NORMAL );
  889.     }
  890.     clear_remaining( filenumber-1 );
  891. }
  892.  
  893. /****************************************************************************
  894.  Draw the border lines
  895. */
  896. void kader( void )
  897. {
  898.     int line;
  899.     char scratch[_MAX_PATH];
  900.     
  901.     _settextwindow( 3, 1, 24, 80 );  /* prevent scroll-up */
  902.     _settextcolor( (short) file_color );
  903.     _settextposition( 1, 1 );
  904.     hide_mouse();
  905.     _outtext("╔════════════     ════════════════════════════════════════════════════     ════╗");
  906.     for (line=2;line<=20;line++)
  907.     {
  908.     _settextposition( line, 1 );
  909.     _outtext("║");
  910.     _settextposition( line, 80 );
  911.     _outtext("║");
  912.     }
  913.     _settextposition( 21, 1 );
  914.     _outtext("╚══════════════════════════════════════════════════════════════════════════════╝");
  915.     if (number_of_files==max_files)
  916.     {
  917.      _settextposition( 21,64 );
  918.      _outtext( "File table full");
  919.     }
  920.     
  921.     _settextposition( 21,14 );
  922.     
  923.     strcpy(scratch," ");
  924.     strncat(scratch,processor,62);
  925.     strcat(scratch," ");
  926.     strlwr(scratch);
  927.     _outtext( scratch );
  928.     
  929.     show_mouse();
  930.     _settextwindow( 3, 1, 23, 80 );
  931. }
  932.  
  933. /**************************************************************************
  934.  Beep
  935. */
  936. void alert( void )
  937. {
  938.     _bios_str( "\007" );
  939. } /* end alert */
  940.  
  941. /****************************************************************************
  942.  * Handler to deal with hard error codes. Since DOS is not reentrant,
  943.  * it is not safe to use DOS calls for doing I/O within the DOS Critical
  944.  * Error Handler (int 24h) used by _harderr. Therefore, screen output and
  945.  * keyboard input must be done through the BIOS.
  946.  * Do not interact with user and return doserr if dos_error_auto_fail is TRUE
  947.  */
  948. void _far hhandler( unsigned deverr, unsigned doserr, unsigned _far *hdr )
  949. {
  950.     int ch;
  951.     unsigned char row=3;
  952.     int itel,itel2;
  953.  
  954.     static char buf[200], tmpbuf[10];
  955.  
  956.     /* save error code */
  957.     dos_error=doserr;
  958.     
  959.     if (dos_error_auto_fail)
  960.     {
  961.       dos_error_auto_fail=FALSE;    /* avoid looping */
  962.       _hardretn( doserr );
  963.     }
  964.     strcpy( buf, " Device error code: " );
  965.     strcat( buf, itoa( deverr, tmpbuf, 10 ) );
  966.     strcat( buf, " " );
  967.     ScrPutS( buf, 0x0f, row++, 1);
  968.     strcpy( buf, " DOS error code   : " );
  969.     strcat( buf, itoa( doserr, tmpbuf, 10 ) );
  970.     strcat( buf, " " );
  971.     ScrPutS( buf, 0x0f, row++, 1);
  972.     if ( allow_abort_on_error) strcpy( buf, " (F) for Fail, (A) to Abort, any other key to Retry ? " );
  973.     else strcpy( buf, " (F) for Fail, any other key to Retry ? " );
  974.     ScrPutS( buf, 0x0f, row++, 1);
  975.  
  976.     _bios_str( "\007" );
  977.     ch = _bios_keybrd( _KEYBRD_READ ) & 0x00ff;
  978.  
  979.     switch( ch )
  980.     {   
  981.         case 'A':
  982.         case 'a': if (allow_abort_on_error) _hardresume( _HARDERR_ABORT );
  983.                   break; 
  984.     case 'F':
  985.     case 'f':       /* Return to DOS with error code */
  986.         dos_retries=0;
  987.         for (itel=3;itel<=6;itel++)          /* blank screen segment */
  988.         for (itel2=1;itel2<=41;itel2++)
  989.             ScrPutS( " ", ((unsigned char) (screen_bg_color * 16)),
  990.                   (unsigned char) itel,(unsigned char) itel2);
  991.         _hardretn( doserr );
  992.     default:        /* Try again */
  993.         dos_retries++;
  994.         strcpy( buf, " Retrying");
  995.         for (itel=0;itel<dos_retries;itel++) strcat( buf,".");
  996.         ScrPutS( buf, 0x0f, row++, 1);
  997.         _hardresume( _HARDERR_RETRY );
  998.     }
  999. }
  1000.  
  1001.  
  1002. /****************************************************************************
  1003.  * Display a string using BIOS interrupt 0x0e (Write TTY). Return length
  1004.  * of string displayed.
  1005.  */
  1006. int _bios_str( char *p )
  1007. {
  1008.     union REGS inregs, outregs;
  1009.     char *start = p;
  1010.  
  1011.     inregs.h.ah = 0x0e;
  1012.     for( ; *p; p++ )
  1013.     {
  1014.     inregs.h.al = *p;
  1015.     int86( 0x10, &inregs, &outregs );
  1016.     }
  1017.     return p - start;
  1018. }
  1019.  
  1020. /*************************************************************************
  1021.  Display an error message, wait one second and blank out message
  1022. */
  1023. void show_error( char *message )
  1024. {
  1025.     char __near *savedscreen;
  1026.     alert();
  1027.     savedscreen=show_string( message, error_bg_color, error_text_color );
  1028.     wait_sec(1000);
  1029.     restScrn(savedscreen); /* remove string box */
  1030. }
  1031.  
  1032. /*************************************************************************
  1033.  Display a message, wait one second and blank out message
  1034. */
  1035. void show_message( char *message )
  1036. {
  1037.     char __near *savedscreen;
  1038.     savedscreen=show_string( message, info_bg_color, info_text_color );
  1039.     wait_sec(1000);
  1040.     restScrn(savedscreen); /* remove string box */
  1041. }
  1042.  
  1043. /*************************************************************************
  1044.  wait, suspend program
  1045. */
  1046. void wait_sec( int milliseconds )
  1047. {
  1048.     clock_t cstart;
  1049.     cstart=clock();
  1050.     while ( (clock()-cstart) < (clock_t) (CLOCKS_PER_SEC/1000) * (clock_t) milliseconds) ;
  1051. }
  1052.  
  1053. /****************************************************************************
  1054.  Displays help information
  1055. */
  1056. void helpscreen( void )
  1057. {
  1058.     int key=0;
  1059.     char b[(19*55)+10]={              /* Buffer for string */
  1060.              "╔════════════════════════════════════════════════════╗\n"
  1061.              "║ FS 2.5 (C) Copyright M.C.J. van Breemen, 1992-1994 ║\n"
  1062.              "╠════════════════════════════════════════════════════╣\n"
  1063.              "║ \x1B\x17\x1A    Move cursor       Del Delete file/dir/label ║\n"
  1064.              "║ Return Select file / CD  I   File information      ║\n"
  1065.              "║ O      Change order      D   Select drive          ║\n"
  1066.              "║ PgUp   Previous screen   R   Rename file/dir/label ║\n"
  1067.              "║ PgDn   Next screen       S   Show file             ║\n"
  1068.              "║ Home   First file        C   Copy file             ║\n"
  1069.              "║ End    Last file         M   Change selection mask ║\n"
  1070.              "║ T      Top directory     X   Temporary exit to DOS ║\n"
  1071.              "║ U      Up one dir.       E   Execute file          ║\n"
  1072.              "║ Alt-AZ Go to filename    A   Change attributes     ║\n"
  1073.              "║ /      Refresh screen    N   Create directory      ║\n"
  1074.              "║ L      Exit & keep dir.  V   Create volume label   ║\n"
  1075.              "║ Esc    Exit / Cancel     F   Disk space free       ║\n"
  1076.              "║ P      About the program W   Where is file         ║\n"
  1077.              "║ B      Since/before date Z   Change file date/time ║\n"
  1078.              "╚════════════════════════════════════════════════════╝\n"
  1079.                };
  1080.     char __near *savedscreen;
  1081.  
  1082.     savedscreen=saveScrn();
  1083.  
  1084.     _settextcolor( (short) info_text_color );
  1085.     _setbkcolor( (long) info_bg_color );
  1086.  
  1087.     paint_box( b, 54, 19);
  1088.  
  1089.     while (!(key=n_kbhit()) && !mouse_button_pressed()) /* wait */ restrict_mouse_topline();
  1090.     _settextwindow( 3, 1, 23, 80 );
  1091.     _setbkcolor( (long) screen_bg_color );
  1092.     savedscreen=restScrn(savedscreen);
  1093.     if ((key & 0x00FF)==ESC) getkey();  /* trash ESC */
  1094. }
  1095.  
  1096. /****************************************************************************
  1097.  Displays program information
  1098. */
  1099. void aboutscreen( void )
  1100. {
  1101.     int key=0;
  1102.     char b[(17*53)+10]={              /* Buffer for string */
  1103.              "╔══════════════════════════════════════════════════╗\n"
  1104.              "║                                                  ║\n"
  1105.              "║             File Selector, Version 2.5           ║\n"
  1106.              "║   Copyright (C) 1992-1994 by M.C.J. van Breemen  ║\n"
  1107.              "║                                                  ║\n"
  1108.              "║             Release date: 27-MAY-1994            ║\n"
  1109.              "║                                                  ║\n"
  1110.              "║          Program designed and written by:        ║\n"
  1111.              "║                                                  ║\n"
  1112.              "║             Maarten van Breemen                  ║\n"
  1113.              "║             Combinatiepolder 13                  ║\n"
  1114.              "║             5235 TR 's-Hertogenbosch             ║\n"
  1115.              "║             The Netherlands                      ║\n"
  1116.              "║                                                  ║\n"
  1117.              "║             CompuServe ID: 100125,2704           ║\n"
  1118.              "║                                                  ║\n"
  1119.              "╚══════════════════════════════════════════════════╝\n"
  1120.                };
  1121.     char __near *savedscreen;
  1122.  
  1123.     savedscreen=saveScrn();
  1124.  
  1125.     _settextcolor( (short) info_text_color );
  1126.     _setbkcolor( (long) info_bg_color );
  1127.  
  1128.     paint_box( b, 52, 17);
  1129.  
  1130.     while (!(key=n_kbhit()) && !mouse_button_pressed()) /* wait */ restrict_mouse_topline();
  1131.     _settextwindow( 3, 1, 23, 80 );
  1132.     _setbkcolor( (long) screen_bg_color );
  1133.     savedscreen=restScrn(savedscreen);
  1134.     if ((key & 0x00FF)==ESC) getkey();  /* trash ESC */
  1135. }
  1136.  
  1137. /*************************************************************************
  1138.  Mouse
  1139. */
  1140. void clear_left_button_queue( void )
  1141. {
  1142.     union REGS in_regs, out_regs;
  1143.     in_regs.x.bx = 0;   /* Clear left button queue */
  1144.     in_regs.x.ax = 5;
  1145.     int86(0x33, &in_regs, &out_regs);
  1146. }
  1147.  
  1148. /*************************************************************************
  1149.  Mouse
  1150. */
  1151. void clear_right_button_queue( void )
  1152. {
  1153.     union REGS in_regs, out_regs;
  1154.     in_regs.x.bx = 1;   /* Clear right button queue */
  1155.     in_regs.x.ax = 5;
  1156.     int86(0x33, &in_regs, &out_regs);
  1157. }
  1158.  
  1159. /*************************************************************************
  1160.  Mouse
  1161.  * Read left button queue
  1162.  * Return 0 if no left button pressed
  1163.  *        1 if pressed but on new position
  1164.  *        2 if re-pressed on old position within 0.75 second
  1165.  */
  1166. int read_left_button_queue( int *row, int *col )
  1167. {
  1168.     union REGS in_regs, out_regs;
  1169.     static int lastrow, lastcol, number_times;
  1170.     static clock_t cstart;
  1171.  
  1172.     in_regs.x.bx = 0;
  1173.     in_regs.x.ax = 5;
  1174.     int86(0x33, &in_regs, &out_regs);
  1175.  
  1176.     number_times = out_regs.x.bx;
  1177.     *row = out_regs.x.dx / 8 + 1;
  1178.     *col = out_regs.x.cx / 8 + 1;
  1179.     if (!number_times) return 0;
  1180.     if (lastrow==*row && lastcol==*col && ((clock()-cstart) < (clock_t) CLOCKS_PER_SEC*2/3))
  1181.     {
  1182.     clear_left_button_queue();
  1183.     cstart=clock();
  1184.     return 2;
  1185.     }
  1186.     lastrow = *row;
  1187.     lastcol = *col;
  1188.     clear_left_button_queue();
  1189.     cstart=clock();
  1190.     return 1;
  1191. }
  1192. /*************************************************************************
  1193.  Mouse
  1194.  * Read right button queue
  1195.  * Return 0 if no right button pressed
  1196.  *        1 if pressed but on new position
  1197.  *        2 if re-pressed on old position within 0.75 second
  1198.  */
  1199. int read_right_button_queue( int *row, int *col )
  1200. {
  1201.     union REGS in_regs, out_regs;
  1202.     static int lastrow, lastcol, number_times;
  1203.     static clock_t cstart;
  1204.  
  1205.     in_regs.x.bx = 1;
  1206.     in_regs.x.ax = 5;
  1207.     int86(0x33, &in_regs, &out_regs);
  1208.  
  1209.     number_times = out_regs.x.bx;
  1210.     *row = out_regs.x.dx / 8 + 1;
  1211.     *col = out_regs.x.cx / 8 + 1;
  1212.     if (!number_times) return 0;
  1213.     if (lastrow==*row && lastcol==*col && ((clock()-cstart) < (clock_t) CLOCKS_PER_SEC*2/3))
  1214.     {
  1215.     clear_right_button_queue();
  1216.     cstart=clock();
  1217.     return 2;
  1218.     }
  1219.     lastrow = *row;
  1220.     lastcol = *col;
  1221.     clear_right_button_queue();
  1222.     cstart=clock();
  1223.     return 1;
  1224. }
  1225.  
  1226. /*********************************************************************88
  1227.  Mouse
  1228. */
  1229. void init_mouse( void )
  1230. {
  1231.     union REGS in_regs, out_regs;
  1232.     int top, bottom, left, right;
  1233.     in_regs.x.ax = 0;           /* Initialize mouse */
  1234.     int86(0x33, &in_regs, &out_regs);
  1235.     if (!out_regs.x.ax)
  1236.     {
  1237.      mouse_present=FALSE;
  1238.      return;
  1239.     }    else mouse_present=TRUE;
  1240.     right = 79;  /* Restrict cursor horizontally */
  1241.     left = 2;
  1242.     in_regs.x.cx = 8 * (right - 1);
  1243.     in_regs.x.dx = 8 * (left - 1);
  1244.     in_regs.x.ax = 7;
  1245.     int86(0x33, &in_regs, &out_regs);
  1246.     top = 4;              /* Restrict cursor vertically */
  1247.     bottom = 22;
  1248.     in_regs.x.cx = 8 * (top - 1);
  1249.     in_regs.x.dx = 8 * (bottom - 1);
  1250.     in_regs.x.ax = 8;
  1251.     int86(0x33, &in_regs, &out_regs);
  1252.     clear_left_button_queue();
  1253.     if (mouse_col)         /* re-position mouse */
  1254.     {
  1255.        in_regs.x.cx = mouse_col;
  1256.        in_regs.x.dx = mouse_row;
  1257.        in_regs.x.ax = 4;
  1258.        int86(0x33, &in_regs, &out_regs);
  1259.     }
  1260.     show_mouse();
  1261. }
  1262.  
  1263. /***************************************************************************8
  1264.  Mouse
  1265. */
  1266. void hide_mouse( void )
  1267. {
  1268.     union REGS in_regs, out_regs;
  1269.     if (!mouse_present) return;
  1270.     /* first save mouse position for possible future mouse_init */
  1271.     in_regs.x.ax = 3;
  1272.     int86(0x33, &in_regs, &out_regs);
  1273.     mouse_col = out_regs.x.cx;
  1274.     mouse_row = out_regs.x.dx;
  1275.  
  1276.     in_regs.x.ax = 2;   /* Hide mouse cursor */
  1277.     int86(0x33, &in_regs, &out_regs);
  1278. }
  1279.  
  1280. /***************************************************************************8
  1281.  Mouse
  1282. */
  1283. void show_mouse( void )
  1284. {
  1285.     union REGS in_regs, out_regs;
  1286.     if (!mouse_present) return;
  1287.     in_regs.x.ax = 1;           /* Show mouse cursor */
  1288.     int86(0x33, &in_regs, &out_regs);
  1289. }
  1290.  
  1291. /*************************************************************************
  1292.  Mouse
  1293.  * Status mouse buttons
  1294.  * Return 0 if no button pressed
  1295.  *        else something is in queue
  1296.  */
  1297. int mouse_button_pressed( void )
  1298. {
  1299.     union REGS in_regs, out_regs;
  1300.  
  1301.     if (!mouse_present) return 0;
  1302.  
  1303.     in_regs.x.bx = 0;
  1304.     in_regs.x.ax = 3;
  1305.     int86(0x33, &in_regs, &out_regs);
  1306.     return( out_regs.x.bx );
  1307. }
  1308.  
  1309. /***************************************************************************
  1310.  Common redraw functions
  1311. */
  1312. void perform_repaint(int current_page, int filenumber)
  1313. {
  1314.     char linebuf[81];
  1315.     int page, max_page;
  1316.     max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  1317.     page=((filenumber%114) ? filenumber/114 : filenumber/114 - 1);
  1318.     _setbkcolor( (long) screen_bg_color );
  1319.     _settextcolor( (short) file_color );
  1320.     hide_mouse();
  1321.     _clearscreen( _GWINDOW );
  1322.     show_mouse();
  1323.     kader();
  1324.     show_path();
  1325.     show_dir_page( current_page );
  1326.     _setbkcolor( (long) screen_bg_color );
  1327.     _settextcolor( (short) file_color );
  1328.     sprintf(linebuf,"%d/%d ",page+1,max_page+1);
  1329.     _settextposition( 1, 72 );
  1330.     outtextm( linebuf );
  1331.     filename( filenumber, CURSOR );  /* emphasize file under cursor */
  1332. }
  1333.  
  1334. /**************************************************************************
  1335.  Cursor movement key handler, page down
  1336. */
  1337. void c_pgdn( int *current_page, int *filenumber)
  1338. {
  1339.    int max_page;
  1340.    int old_current_page;
  1341.  
  1342.    old_current_page = *current_page;
  1343.    max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  1344.    if (*current_page<max_page) (*current_page)++;
  1345.    else *current_page=0;
  1346.  
  1347.    if (*current_page != old_current_page)
  1348.    {
  1349.        show_dir_page( *current_page );
  1350.        *filenumber=((*current_page)*114+1);
  1351.        filename( *filenumber, CURSOR );
  1352.    }
  1353. }
  1354.  
  1355. /**************************************************************************
  1356.  Cursor movement key handler, page up
  1357. */
  1358. void c_pgup( int *current_page, int *filenumber)
  1359. {
  1360.     int max_page;
  1361.     int old_current_page;
  1362.  
  1363.     old_current_page = *current_page;
  1364.     max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  1365.     if (*current_page>0) (*current_page)--;
  1366.     else *current_page=max_page;
  1367.  
  1368.     if (*current_page != old_current_page)
  1369.     {
  1370.     show_dir_page( *current_page );
  1371.     *filenumber=((*current_page)*114+1);
  1372.     filename( *filenumber, CURSOR );
  1373.     }
  1374. }
  1375.  
  1376. /**************************************************************************
  1377.  Cursor movement key handler, home
  1378. */
  1379. void c_home( int *current_page, int *filenumber)
  1380. {
  1381.      *current_page=0;
  1382.      show_dir_page( *current_page );
  1383.      *filenumber=((*current_page)*114+1);
  1384.      filename( *filenumber, CURSOR );
  1385. }
  1386.  
  1387. /**************************************************************************
  1388.  Find and display file with starting character chr
  1389. */
  1390. void find_first(char chr, int *current_page, int *filenumber)
  1391. {
  1392.      register int counter;
  1393.      int old_page;
  1394.      int old_filenumber;
  1395.      if (!number_of_files) return;
  1396.      old_page=*current_page;
  1397.      old_filenumber=*filenumber;
  1398.      for (counter=1;counter<number_of_files;counter++) /* should end at last file */
  1399.        if (find[counter].name[0]>=chr) break;
  1400.      *filenumber=counter;
  1401.      *current_page=((counter%114) ? counter/114 : counter/114 - 1);
  1402.      if (*current_page!=old_page) perform_repaint(*current_page,*filenumber);
  1403.      else
  1404.      {
  1405.     if (*filenumber!=old_filenumber)
  1406.     {
  1407.         filename( old_filenumber, NORMAL );
  1408.         filename( *filenumber, CURSOR );
  1409.     }
  1410.      }
  1411. }
  1412.  
  1413. /**************************************************************************
  1414.  Cursor movement key handler, end
  1415. */
  1416. void c_end( int *current_page, int *filenumber)
  1417. {
  1418.      int max_page;
  1419.      max_page=((number_of_files%114) ? number_of_files/114 : number_of_files/114 - 1);
  1420.      *current_page=max_page;
  1421.      show_dir_page( *current_page );
  1422.      *filenumber=((*current_page)*114+114);
  1423.      *filenumber=(*filenumber<number_of_files) ? *filenumber : number_of_files;
  1424.      filename( *filenumber, CURSOR );
  1425. }
  1426.  
  1427. /**************************************************************************
  1428.  Cursor movement key handler, up arrow
  1429. */
  1430. void c_cup( int *current_page, int *filenumber)
  1431. {
  1432.    int old_filenumber;
  1433.    old_filenumber=*filenumber;
  1434.    if (*filenumber>((*current_page)*114+1)) (*filenumber)--;
  1435.    else
  1436.    {
  1437.     *filenumber=((*current_page)*114+114);
  1438.     *filenumber=(*filenumber<number_of_files) ? *filenumber : number_of_files;
  1439.    }
  1440.    if (*filenumber!=old_filenumber)
  1441.    {
  1442.     filename( old_filenumber, NORMAL );
  1443.     filename( *filenumber, CURSOR );
  1444.    }
  1445. }
  1446.  
  1447. /**************************************************************************
  1448.  Cursor movement key handler, down arrow
  1449. */
  1450. void c_cdn( int *current_page, int *filenumber)
  1451. {
  1452.    int old_filenumber;
  1453.    old_filenumber=*filenumber;
  1454.    if (*filenumber<((*current_page)*114+114) &&
  1455.        *filenumber<number_of_files) (*filenumber)++;
  1456.     else *filenumber=((*current_page)*114+1);
  1457.    filename( old_filenumber, NORMAL );
  1458.    filename( *filenumber, CURSOR );
  1459. }
  1460.  
  1461. /**************************************************************************
  1462.  Cursor movement key handler , right arrow
  1463. */
  1464. void c_cri( int *current_page, int *filenumber)
  1465. {
  1466.     int old_filenumber;
  1467.     old_filenumber=*filenumber;
  1468.     if ((*filenumber <= ((*current_page)*114+95)) &&
  1469.     ((*filenumber+19) <= number_of_files)) (*filenumber)+=19;
  1470.     else
  1471.     {
  1472.     (*filenumber)%=19;
  1473.     if (!(*filenumber)) *filenumber=19;
  1474.     (*filenumber)+=((*current_page)*114);
  1475.     }
  1476.     if (*filenumber!=old_filenumber)
  1477.     {
  1478.     filename( old_filenumber, NORMAL );
  1479.     filename( *filenumber, CURSOR );
  1480.     }
  1481. }
  1482.  
  1483. /**************************************************************************
  1484.  Cursor movement key handler, left arrow
  1485. */
  1486. void c_cle( int *current_page, int *filenumber)
  1487. {
  1488.     int old_filenumber;
  1489.     int maxcolumnnumber;
  1490.     old_filenumber=*filenumber;
  1491.     if (*filenumber>=((*current_page)*114+1)+19) (*filenumber)-=19;
  1492.     else
  1493.     {
  1494.     maxcolumnnumber=5;
  1495.     while ((*filenumber+maxcolumnnumber*19)>number_of_files) maxcolumnnumber--;
  1496.     (*filenumber)+=maxcolumnnumber*19;
  1497.     }
  1498.     if (*filenumber!=old_filenumber)
  1499.     {
  1500.     filename( old_filenumber, NORMAL );
  1501.     filename( *filenumber, CURSOR );
  1502.     }
  1503. }
  1504.  
  1505.  
  1506. /***********************************************************************
  1507.  returns 0 if no key waiting, key code if key waiting
  1508. */
  1509. unsigned int n_kbhit()
  1510. {
  1511.     int kread = _KEYBRD_READ;
  1512.     int kready = _KEYBRD_READY;
  1513.     int kshiftstatus = _KEYBRD_SHIFTSTATUS;
  1514.  
  1515.     /* If bit 4 of the byte at 0x0040:0x0096 is set, the new keyboard
  1516.      * is present.
  1517.      */
  1518.     if( peek( 0x00400096 ) & 0x10 )
  1519.     {
  1520.     kread = _NKEYBRD_READ;
  1521.     kready = _NKEYBRD_READY;
  1522.     kshiftstatus = _NKEYBRD_SHIFTSTATUS;
  1523.     }
  1524.     return _bios_keybrd( kready );
  1525. }
  1526.  
  1527. /************************************************************************
  1528.  Entry point of directory handler
  1529.  Globals: find, files structure
  1530.       number_of_files
  1531.       colors
  1532.  Returns SUCCESS if a valid choice has been made, else EXIT_RESTORE if ESCaped
  1533.  or EXIT_KEEP if Leaved
  1534.  Passes selected file in string selected
  1535. */
  1536. int handle_dir( char *searchstr, char *selected , int safe_mode)
  1537. {
  1538.     int key;
  1539.     int repaint;
  1540.     static int current_page=0;
  1541.     static int filenumber=1;
  1542.     int old_filenumber;
  1543.     short  oldfgd;               /* old foreground color */
  1544.     long   oldbgd;               /* old background color */
  1545.     struct rccoord oldpos;
  1546.     short oldcursor;             /* old cursor shape */
  1547.     int olddrive, lastdrive, newdrive;
  1548.     char oldcwd[_MAX_PATH];
  1549.     int row, col;                       /* mouse variables */
  1550.     int finished;
  1551.     struct videoconfig vc;
  1552.     char scratch[ _MAX_PATH ];          /* scratch string space */
  1553.     int exit_and_keep=FALSE;            /* boolean for 'l' function */
  1554.     char __near *dummyspace;            /* memory reserved for saveScrn */
  1555.     struct diskfree_t drvinfo;
  1556.     char comspec[_MAX_PATH];
  1557.     int huge_find=FALSE;                /* first try to use near heap memory */
  1558.     int old_order_by;                   /* old info could still be valid */
  1559.     char __near *savedscreen;
  1560.     int mouse_clicks;
  1561.     void __near *nearfind;              /* needed to free the near heap memory */
  1562.     unsigned int shift;
  1563.                       
  1564.     if (!safe_mode) allow_abort_on_error=TRUE;
  1565.                           
  1566.     strcpy(comspec,getenv("COMSPEC"));
  1567.     if (!strlen(comspec)) strcpy(comspec,"COMMAND"); /* default program to run is COMMAND.COM */
  1568.  
  1569.     /* Save original foreground, background, and text position. */
  1570.     init_mouse();
  1571.     oldfgd = _gettextcolor();
  1572.     oldbgd = _getbkcolor();
  1573.     oldpos = _gettextposition();
  1574.     oldcursor=_gettextcursor();
  1575.     _settextcursor( 0x2000 );
  1576.     _settextwindow( 3, 1, 23, 80 );
  1577.  
  1578.     _getvideoconfig( &vc );
  1579.  
  1580.     if (vc.mode==_TEXTMONO)
  1581.     {
  1582.     screen_bg_color   = M_BLACK_BG;
  1583.     file_color        = M_GRAY;
  1584.     hidden_file_color = M_GRAY;
  1585.     directory_color   = M_WHITE;
  1586.     hidden_directory_color       = M_WHITE;
  1587.     volume_label_color= M_GRAY;
  1588.     cursor_bg_color   = M_BLACK_BG;
  1589.     info_bg_color     = M_BLACK_BG;
  1590.     info_text_color   = M_WHITE;
  1591.     error_bg_color    = M_BLACK_BG;
  1592.     error_text_color  = M_WHITE;
  1593.     cursor_bg_color              = M_BLACK_BG;
  1594.     cursor_file_color            = M_GRAY_UNDL;
  1595.     cursor_directory_color       = M_WHITE_UNDL;
  1596.     cursor_hidden_file_color     = M_GRAY_UNDL;
  1597.     cursor_hidden_directory_color= M_WHITE_UNDL;
  1598.     cursor_volume_label_color    = M_GRAY_UNDL;
  1599.     }
  1600.     else
  1601.     {
  1602.         cursor_file_color            = file_color;
  1603.         cursor_directory_color       = directory_color;
  1604.         cursor_hidden_file_color     = hidden_file_color;
  1605.         cursor_hidden_directory_color= hidden_directory_color;
  1606.         cursor_volume_label_color    = volume_label_color;
  1607.     }
  1608.  
  1609.  
  1610.     if (!strlen(searchstring)) strcpy(searchstring,searchstr); /* keep old definition */
  1611.     if (!strlen(searchstring)) strcpy(searchstring,"*.*");
  1612.     find=(FIND_T_SMALL *) 0L;
  1613.     if (max_files<=0) max_files=MAX_FILES;
  1614.  
  1615.     dummyspace = (char __near *) _nmalloc (4096+1024); /* alloceer ruimte voor screen saves, near heap copy */
  1616.  
  1617.     if ( (((long) max_files + 2) * (long) sizeof(FIND_T_SMALL)) >= (long) _memmax() || huge_find)
  1618.     {
  1619.       if ( !(find = _halloc( ((long) max_files + 2), (size_t) sizeof(FIND_T_SMALL) )) )
  1620.       {
  1621.     _settextwindow( 1, 1, 25, 80 );
  1622.     _settextposition( oldpos.row, oldpos.col );
  1623.     _settextcursor( oldcursor );
  1624.     printf("Cannot allocate far heap memory for %d files ",max_files);
  1625.     alert();
  1626.     hide_mouse();
  1627.     default_mouse_rectangle();
  1628.     wait_sec(1000);
  1629.     if (dummyspace) _nfree(dummyspace);
  1630.     return FAILURE;
  1631.       }
  1632.       huge_find=TRUE;
  1633.     }
  1634.     else
  1635.     {
  1636.       find = (FIND_T_SMALL *) _ncalloc( (size_t) max_files + 2, (size_t) sizeof(FIND_T_SMALL) );
  1637.       if( !(((long) find) & 0x0000FFFF) ) /* 16 bits NULL if failed */ 
  1638.       {
  1639.     if (dummyspace) _nfree(dummyspace);
  1640.     _settextwindow( 1, 1, 25, 80 );
  1641.     _settextposition( oldpos.row, oldpos.col );
  1642.     _settextcursor( oldcursor );
  1643.     printf("Cannot allocate near heap memory for %d files ",max_files);
  1644.     alert();
  1645.     hide_mouse();
  1646.     wait_sec(1000);
  1647.     return FAILURE;
  1648.       }
  1649.       huge_find=FALSE;
  1650.     }
  1651.     if (dummyspace) _nfree(dummyspace);
  1652.     /* hoppa, we hebben weer lucht */
  1653.  
  1654.     /* Install our hard error handler. */
  1655.     _harderr( hhandler );
  1656.  
  1657.     /* Save current drive and current working directory. */
  1658.     olddrive = lastdrive = _getdrive();
  1659.     getcwd( oldcwd, _MAX_PATH );
  1660.  
  1661.     repaint=TRUE;
  1662.     extract_directory( searchstring );
  1663.     if (filenumber>number_of_files)     /* can we restore the cursor ? */
  1664.     {
  1665.     current_page=0;                 /* no */
  1666.     filenumber=1;
  1667.     }
  1668.     finished=FALSE;
  1669.     do
  1670.     {
  1671.     dos_error=0;
  1672.     dos_retries=0;
  1673.  
  1674.     if (repaint)
  1675.     {
  1676.          /* maak kader repaint */
  1677.          perform_repaint(current_page, filenumber);
  1678.          repaint=FALSE;
  1679.     }
  1680.  
  1681.     if (mouse_present)
  1682.     {
  1683.  
  1684.       restrict_mouse_topline();
  1685.  
  1686.       mouse_clicks = read_left_button_queue(&row,&col);
  1687.       if (row>3)
  1688.       {
  1689.         switch (mouse_clicks)
  1690.         {
  1691.         case 0: break;
  1692.         case 1: if (!number_of_files) break;
  1693.             old_filenumber=filenumber;
  1694.             filenumber=(row-4)+(current_page*114+1)+((col-2)/13)*19;
  1695.             if (filenumber>number_of_files) filenumber=old_filenumber;
  1696.             if (filenumber!=old_filenumber)
  1697.             {
  1698.             filename( old_filenumber, NORMAL );
  1699.             filename( filenumber, CURSOR );
  1700.             }
  1701.             break;
  1702.         case 2: if (!number_of_files) break;
  1703.             old_filenumber=filenumber;
  1704.             filenumber=(row-4)+(current_page*114+1)+((col-2)/13)*19;
  1705.             if (filenumber<=number_of_files)
  1706.             {
  1707.             if (filename( filenumber, NOREPAINT )=='D')
  1708.             {
  1709.                repaint=TRUE;
  1710.                if (!strcmp(find[filenumber].name,"..")) /* going up */
  1711.                {
  1712.                    find_parent( ¤t_page, &filenumber, searchstring);
  1713.                }
  1714.                else  /* going down */
  1715.                {
  1716.                 chdir( find[filenumber].name );
  1717.                 extract_directory( searchstring );
  1718.                 current_page=0;
  1719.                 filenumber=1;
  1720.                }
  1721.             } else finished=TRUE; /* add normal file handling here */
  1722.             } else filenumber=old_filenumber;
  1723.             break;
  1724.         }
  1725.       }
  1726.       else
  1727.       {
  1728.           /* page down */
  1729.           if (mouse_clicks)
  1730.           {
  1731.           if (number_of_files) c_pgdn( ¤t_page, &filenumber);
  1732.           }
  1733.       }
  1734.  
  1735.       mouse_clicks = read_right_button_queue(&row,&col);
  1736.       if (mouse_clicks && row>3 && number_of_files) /* right button */
  1737.       { 
  1738.         working(TRUE);
  1739.         getpath( _getdrive(), scratch, _MAX_PATH );
  1740.         working(FALSE);
  1741.         if (strlen(scratch)>3)
  1742.         {
  1743.            repaint=TRUE;
  1744.            find_parent( ¤t_page, &filenumber,searchstring);
  1745.         }
  1746.       }
  1747.       else
  1748.       {
  1749.           /* page up */
  1750.           if (mouse_clicks)
  1751.           {
  1752.           if (number_of_files) c_pgup( ¤t_page, &filenumber);
  1753.           }
  1754.       }
  1755.  
  1756.     }
  1757.  
  1758.        if (n_kbhit() && !finished)
  1759.        {
  1760.     key = getkey();
  1761.     if (key<256) key = tolower(key);
  1762.     if (key=='l' && !safe_mode)     /* leave FS here */
  1763.     {
  1764.          exit_and_keep=TRUE;
  1765.          key=ESC;
  1766.     }
  1767.     if (key==ESC) break;     /* ESC, exit do while TRUE loop */
  1768.     repaint=FALSE;
  1769.     switch (key)
  1770.     {
  1771.         case 'i': if (number_of_files) fileinfo( filenumber );
  1772.               break;
  1773.         case 'h':
  1774.         case '?': helpscreen();
  1775.               break;
  1776.         case 'p': aboutscreen();
  1777.               break;
  1778.         case 'a': if (safe_mode) break;
  1779.               if (number_of_files)
  1780.               {
  1781.                 switch (ed_attributes(filenumber))
  1782.                 {
  1783.               case FAILURE: show_error("Cannot change attributes");
  1784.                     break;                  
  1785.               case SUCCESS: repaint=TRUE;
  1786.                     extract_directory( searchstring );
  1787.                     if (filenumber > number_of_files)
  1788.                     {
  1789.                         filenumber=1;
  1790.                         current_page=0;
  1791.                     }
  1792.                     break;
  1793.               case NOCHANGE: break;
  1794.                 }
  1795.               }  
  1796.               break;
  1797.         case 'z': if (safe_mode) break;
  1798.               if (number_of_files)
  1799.               {
  1800.                 switch (ed_datetime(filenumber))
  1801.                 {
  1802.               case FAILURE: show_error("Cannot change date and time");
  1803.                     break;                  
  1804.               case SUCCESS: repaint=TRUE;
  1805.                     extract_directory( searchstring );
  1806.                     if (filenumber > number_of_files)
  1807.                     {
  1808.                         filenumber=1;
  1809.                         current_page=0;
  1810.                     }
  1811.                     break;
  1812.               case NOCHANGE: break;
  1813.                 }
  1814.               }
  1815.               break;
  1816.         case 'b': if (number_of_files)
  1817.               {
  1818.                 switch (ed_turnover_datetime())
  1819.                 {
  1820.               case FAILURE: show_error("Illegal date-time format");
  1821.                     break;                  
  1822.               case SUCCESS: repaint=TRUE;
  1823.                     extract_directory( searchstring );
  1824.                     if (filenumber > number_of_files)
  1825.                     {
  1826.                         filenumber=1;
  1827.                         current_page=0;
  1828.                     }
  1829.                     break;
  1830.               case NOCHANGE: break;
  1831.                 }
  1832.               }
  1833.               break;
  1834.         case 'o': if (number_of_files)
  1835.               {
  1836.               old_order_by=order_by;
  1837.               strcpy(scratch,"");
  1838.               switch(order_by)
  1839.               {
  1840.                  case NAME: strcpy(scratch,"N");
  1841.                     break;
  1842.                  case DATE: strcpy(scratch,"D");
  1843.                     break;
  1844.                  case SIZE: strcpy(scratch,"S");
  1845.                     break;
  1846.               }
  1847.               if (order_by != NONE)
  1848.               {
  1849.                 switch(order_type)
  1850.                 {
  1851.                    case ASCENDING: strcat(scratch,"+");
  1852.                            break;
  1853.                    case DESCENDING: strcat(scratch,"-");
  1854.                         break;
  1855.                 }
  1856.               }
  1857.               if (edit("Order by (N)ame, (D)ate or (S)ize. Order + or -",scratch,3,
  1858.                  "NDSnds+-",LEGAL))
  1859.               {
  1860.                 strupr(scratch);
  1861.                 if (!strlen(scratch)) order_by=NONE;
  1862.                 if (strchr(scratch,(int) 'N')) order_by=NAME;
  1863.                 if (strchr(scratch,(int) 'S')) order_by=SIZE;
  1864.                 if (strchr(scratch,(int) 'D')) order_by=DATE;
  1865.                 if (strchr(scratch,(int) '-')) order_type=DESCENDING;
  1866.                 if (strchr(scratch,(int) '+')) order_type=ASCENDING;
  1867.                 repaint=TRUE;
  1868.                 if (order_by != NONE &&
  1869.                 (old_order_by==order_by || (old_order_by!=SIZE && order_by!=SIZE)))
  1870.                 {
  1871.                 working(TRUE);
  1872.                 put_parent_on_top(order_type);
  1873.                 qsort( (void *) (&(find[1])), (size_t) number_of_files,
  1874.                        (size_t) sizeof(FIND_T_SMALL), cmpgle); /* still valid */
  1875.                 make_parent_two_dots();
  1876.                 working(FALSE);
  1877.                 }
  1878.                 else
  1879.                 {
  1880.                 extract_directory( searchstring );
  1881.                 if (filenumber > number_of_files)
  1882.                 {
  1883.                     filenumber=1;
  1884.                     current_page=0;
  1885.                 }
  1886.                 }
  1887.               }
  1888.               }
  1889.               break;
  1890.         case K_PGDN: if (number_of_files) c_pgdn( ¤t_page, &filenumber);
  1891.              break;
  1892.         case K_PGUP: if (number_of_files) c_pgup( ¤t_page, &filenumber);
  1893.              break;
  1894.         case K_HOME: if (number_of_files) c_home( ¤t_page, &filenumber);
  1895.              break;
  1896.         case K_END: if (number_of_files) c_end( ¤t_page, &filenumber);
  1897.             break;
  1898.         case K_CUP: if (number_of_files) c_cup( ¤t_page, &filenumber);
  1899.             break;
  1900.         case K_CDN: if (number_of_files) c_cdn( ¤t_page, &filenumber);
  1901.             break;
  1902.         case K_CRI: if (number_of_files) c_cri( ¤t_page, &filenumber);
  1903.             break;
  1904.         case K_CLE: if (number_of_files) c_cle( ¤t_page, &filenumber);
  1905.             break;
  1906.         case '\r': if (!number_of_files) break;
  1907.                repaint=TRUE;
  1908.                if (filename( filenumber, NOREPAINT )=='D')
  1909.                {
  1910.                if (!strcmp(find[filenumber].name,"..")) /* going up */
  1911.                {
  1912.                    find_parent( ¤t_page, &filenumber,searchstring);
  1913.                }
  1914.                else  /* going down */
  1915.                {
  1916.                    chdir( find[filenumber].name );
  1917.                    extract_directory( searchstring );
  1918.                    current_page=0;
  1919.                    filenumber=1;
  1920.                }
  1921.                } else finished=TRUE; /* add normal file handling here */
  1922.                break;
  1923.         case 'u':  if (!number_of_files) break;
  1924.                working(TRUE);
  1925.                getpath( _getdrive(), scratch, _MAX_PATH );
  1926.                working(FALSE);
  1927.                if (strlen(scratch)>3)
  1928.                {
  1929.                repaint=TRUE;
  1930.                find_parent( ¤t_page, &filenumber,searchstring);
  1931.                }
  1932.                break;
  1933.         case 't': if (!number_of_files) break;
  1934.               working(TRUE);
  1935.               getpath( _getdrive(), scratch, _MAX_PATH );
  1936.               working(FALSE);
  1937.               if (strlen(scratch)>3)
  1938.               {
  1939.               repaint=TRUE;
  1940.               scratch[0]= (char) (_getdrive() - 1 + 'A');
  1941.               scratch[1]=':';
  1942.               scratch[2]='\\';
  1943.               scratch[3]='\0';
  1944.               chdir( scratch );
  1945.               extract_directory( searchstring );
  1946.               current_page=0;
  1947.               filenumber=1;
  1948.               }
  1949.               break;
  1950.         case 'x': if (safe_mode) break;
  1951.               hide_mouse();
  1952.               default_mouse_rectangle();
  1953.               _settextcolor( oldfgd );
  1954.               _setbkcolor( oldbgd );
  1955.               _clearscreen( _GCLEARSCREEN );
  1956.               _settextcursor( oldcursor );
  1957.               lastdrive = _getdrive();
  1958.               strcpy(scratch,"PROMPT=Type EXIT to return to FS$_$p$g");
  1959.               putenv(scratch);
  1960.               if (allow_swap) fs_systemo(swap_dir,"");
  1961.               else system(comspec);
  1962.               _harderr( hhandler );
  1963.               init_mouse();
  1964.               _settextcursor( 0x2000 );
  1965.               _chdrive( lastdrive );
  1966.               extract_directory( searchstring );
  1967.               if (filenumber>number_of_files)   /* can we restore the cursor ? */
  1968.               {
  1969.               current_page=0;
  1970.               filenumber=1;
  1971.               }
  1972.               repaint=TRUE;
  1973.               break;
  1974.  
  1975.         case 'f': working(TRUE);
  1976.               if (freespace( scratch )==SUCCESS)
  1977.               {
  1978.                working(FALSE);
  1979.                _settextposition( 23, 26 );
  1980.                savedscreen=show_string( scratch , info_bg_color, info_text_color );
  1981.                while (!n_kbhit() && !mouse_button_pressed()) /* wait */ restrict_mouse_topline();
  1982.                restScrn(savedscreen);       /* remove string box */
  1983.               } else
  1984.               {
  1985.                show_error("Cannot get disk information from this drive");
  1986.                working(FALSE);
  1987.               }
  1988.               break;
  1989.         case 'd': newdrive=ask_drive_number(" Type new drive letter or ESC ");
  1990.               lastdrive = _getdrive();
  1991.               if (newdrive==-1) break;
  1992.  
  1993.               do
  1994.               {
  1995.               /* start excessive error checking to prevent */
  1996.               /* triggering the dos error handler */
  1997.               while (newdrive==-1)
  1998.               {
  1999.                   newdrive=ask_drive_number(" Type new valid drive letter ");
  2000.               }
  2001.               working(TRUE);
  2002.               dos_error=0;
  2003.               dos_retries=0;
  2004.               dos_error_auto_fail=TRUE;
  2005.  
  2006.               if (!drvalid(newdrive-1) || dos_error)
  2007.               {
  2008.                   working(FALSE);
  2009.                   show_error("Cannot change to this drive");
  2010.                   newdrive=-1;
  2011.                   continue;     /* and again */
  2012.               }
  2013.  
  2014.               dos_error=0;
  2015.               dos_retries=0;
  2016.               if (newdrive==1 || newdrive==2)
  2017.               {
  2018.                   if (floptest(newdrive-1)) /* checks drive A or B */
  2019.                   {
  2020.                   working(FALSE);
  2021.                   show_error("Cannot select this drive");
  2022.                   newdrive=-1;
  2023.                   continue;             /* again */
  2024.                   }
  2025.               }
  2026.  
  2027.               dos_error_auto_fail=TRUE;
  2028.               _dos_getdiskfree( newdrive, &drvinfo );
  2029.               if (dos_error)
  2030.               {
  2031.                   working(FALSE);
  2032.                   show_error("Cannot get disk information from this drive");
  2033.                   newdrive=-1;
  2034.                   continue;     /* and again */
  2035.               }
  2036.  
  2037.               dos_error_auto_fail=FALSE;
  2038.               lastdrive=newdrive;   /* YES, successfull, get out */
  2039.               break;
  2040.               } while (TRUE);
  2041.  
  2042.               working(FALSE);
  2043.               extract_directory( searchstring );
  2044.               current_page=0;
  2045.               filenumber=1;
  2046.               repaint=TRUE;
  2047.               break;
  2048.         case K_DEL: if (safe_mode) break;
  2049.             if (!number_of_files) break;
  2050.             if (!strcmp(find[filenumber].name,"..")) break;  /* this could give you a lot of free space */
  2051.             savedscreen=show_string("Type Y to delete or any other key to cancel", info_bg_color, info_text_color);
  2052.             _settextposition( 1, 1 );        /* prevent scroll-up from dos error */
  2053.             key = getkey();
  2054.             restScrn(savedscreen);  /* remove string box */
  2055.  
  2056.             if (key=='y' || key=='Y')
  2057.             {  
  2058.                working(TRUE);
  2059.                dos_error_auto_fail=TRUE; 
  2060.                if (filename( filenumber, NOREPAINT )=='D')
  2061.                {
  2062.                 if (rmdir(find[filenumber].name)) /* first try normal delete, will fail if not empty */
  2063.                 {                                 /* then try to clean up */
  2064.                        working(FALSE); 
  2065.                        savedscreen=show_string("Directory contains files.\n║ Type Y to delete, any other key to cancel",info_bg_color,info_text_color);
  2066.                        _settextposition( 1, 1 );          /* prevent scroll-up from dos error */
  2067.                        key = getkey();
  2068.                        restScrn(savedscreen);   /* remove string box */
  2069.                        if (key=='y' || key=='Y')
  2070.                        { 
  2071.                        working(TRUE);
  2072.                        do_dir(find[filenumber].name);
  2073.                        working(FALSE);
  2074.                        }
  2075.                 }
  2076.                dos_error_auto_fail=FALSE;
  2077.                }
  2078.                else
  2079.                {
  2080.                 dos_error_auto_fail=TRUE;
  2081.                 working(TRUE);
  2082.                 if (filename( filenumber, NOREPAINT )=='V')
  2083.                 {
  2084.                     if (FilDelVolid( (unsigned char) _getdrive() )==NODEL)
  2085.                        show_error("Cannot delete this volume label");
  2086.                 }
  2087.                 else
  2088.                 {
  2089.                     if (unlink(find[filenumber].name))
  2090.                        show_error("Cannot delete this file");
  2091.                 }
  2092.                 dos_error_auto_fail=FALSE;
  2093.                 working(FALSE);
  2094.                }
  2095.                extract_directory( searchstring );
  2096.                if (filenumber > number_of_files) /* we lost the file under the cursor */
  2097.                {
  2098.                    if (number_of_files)
  2099.                   c_end( ¤t_page, &filenumber);
  2100.                }
  2101.                working(FALSE); 
  2102.                repaint=TRUE;
  2103.             }
  2104.               break;
  2105.         case '/': repaint=TRUE;
  2106.               extract_directory( searchstring );
  2107.               if (filenumber > number_of_files)
  2108.               {
  2109.               filenumber=1;
  2110.               current_page=0;
  2111.               }
  2112.               break;
  2113.         case 'v': if (safe_mode) break;
  2114.               dos_error_auto_fail=TRUE;
  2115.               switch (rename_volume_label(0)) /* use dummy zero index */
  2116.               {
  2117.                   case FAILURE: show_error("Cannot create this volume label");
  2118.                         break;
  2119.                   case SUCCESS: repaint=TRUE;
  2120.                         extract_directory( searchstring );
  2121.                         if (filenumber > number_of_files)
  2122.                         {
  2123.                         filenumber=1;
  2124.                         current_page=0;
  2125.                         }
  2126.                         break;
  2127.                   case NOCHANGE: break;
  2128.               }
  2129.               dos_error_auto_fail=FALSE;
  2130.               break;
  2131.         case 's': if (number_of_files)
  2132.               {   
  2133.                  hide_mouse();
  2134.                  shift=getshift();
  2135.                          if ((shift & 1) || (shift & 2))  /* left or right shift is down */
  2136.                          {
  2137.                              if (old_show_file( find[filenumber].name)==SUCCESS)
  2138.                     repaint=TRUE;
  2139.              } else if (show_file( find[filenumber].name)==SUCCESS)
  2140.                        repaint=TRUE;
  2141.                  show_mouse();
  2142.               }               
  2143.               break;
  2144.         case 'e': if (safe_mode) break;
  2145.               if (!number_of_files) break;
  2146.               strcpy(scratch,find[filenumber].name);
  2147.               strcat(scratch," ");
  2148.               scratch[strlen(scratch)+1]='\0';
  2149.               if (edit("Enter command-line arguments, ESC to cancel",scratch+strlen(scratch),48,"", ILLEGAL))
  2150.               {
  2151.              hide_mouse();
  2152.              default_mouse_rectangle();
  2153.              repaint=TRUE;
  2154.              _settextcolor( oldfgd );
  2155.              _setbkcolor( oldbgd );
  2156.              _settextcursor( oldcursor );
  2157.              lastdrive = _getdrive();
  2158.              _clearscreen( _GCLEARSCREEN ); 
  2159.              if (allow_swap) fs_systemo(swap_dir,scratch);
  2160.              else system(scratch);
  2161.              _settextcolor( (short) info_text_color );
  2162.              _setbkcolor( (long) screen_bg_color );
  2163.              _settextposition( 23, 25 );
  2164.              outtextm(" Press any key to continue ");
  2165.              getkey();
  2166.  
  2167.              _harderr( hhandler );
  2168.              init_mouse();
  2169.              _settextcursor( 0x2000 );
  2170.              extract_directory( searchstring );
  2171.              if (filenumber>number_of_files)         /* can we restore the cursor ? */
  2172.              {
  2173.                  current_page=0;
  2174.                  filenumber=1;
  2175.              }
  2176.               }
  2177.               break;
  2178.         case 'm': strcpy(scratch,searchstring);
  2179.               if (edit("Enter a filename mask, ESC to cancel",searchstring, 12,":\\ +=[];|,<>/\"",ILLEGAL))
  2180.               {
  2181.              if (strcmp(searchstring,scratch))
  2182.              {
  2183.                extract_directory( searchstring );
  2184.                if (filenumber>number_of_files)      /* can we restore the cursor ? */
  2185.                {
  2186.                    current_page=0;
  2187.                    filenumber=1;
  2188.                }
  2189.                repaint=TRUE;
  2190.              }
  2191.               }
  2192.               break;
  2193.         case 'r': if (safe_mode) break;
  2194.               if (number_of_files)
  2195.               {
  2196.             dos_error_auto_fail=TRUE;
  2197.             if (filename( filenumber, NOREPAINT )=='V')
  2198.             {
  2199.                 switch (rename_volume_label(filenumber))
  2200.                 {
  2201.                   case FAILURE: show_error("Cannot rename this volume label");
  2202.                         break;
  2203.                   case SUCCESS: repaint=TRUE;
  2204.                         extract_directory( searchstring );
  2205.                         if (filenumber > number_of_files)
  2206.                         {
  2207.                         filenumber=1;
  2208.                         current_page=0;
  2209.                         }
  2210.                         break;
  2211.                   case NOCHANGE: break;
  2212.                 }
  2213.             }
  2214.             else switch (rename_file(filenumber))  /* file or dir */
  2215.             {
  2216.               case FAILURE: show_error("Cannot rename this file");
  2217.                     break;
  2218.               case SUCCESS: repaint=TRUE;
  2219.                     extract_directory( searchstring );
  2220.                     if (filenumber > number_of_files)
  2221.                     {
  2222.                         c_end( ¤t_page, &filenumber);
  2223.                     }
  2224.                     break;
  2225.               case NOCHANGE: break;
  2226.             }
  2227.             dos_error_auto_fail=FALSE;
  2228.               }
  2229.               break;
  2230.         case 'n': if (safe_mode) break;
  2231.               switch (make_directory())
  2232.               {
  2233.               case FAILURE: show_error("Cannot create this directory");
  2234.                     break;
  2235.               case SUCCESS: repaint=TRUE;
  2236.                     extract_directory( searchstring );
  2237.                     if (filenumber > number_of_files)
  2238.                     {
  2239.                         filenumber=1;
  2240.                         current_page=0;
  2241.                     }
  2242.                     break;
  2243.               case NOCHANGE: break;
  2244.               }
  2245.               break;
  2246.         case 'w': switch (whereis(searchstring, ¤t_page, &filenumber))
  2247.               {
  2248.               case U_SELECT: finished=TRUE;
  2249.                      break;
  2250.               case U_GOTO: repaint=TRUE;
  2251.                        break;
  2252.               case FAILURE: repaint=TRUE;
  2253.                     show_error( "File find failed");
  2254.                     extract_directory( searchstring );
  2255.                     if (filenumber > number_of_files)
  2256.                     {
  2257.                          filenumber=1;
  2258.                          current_page=0;
  2259.                     }
  2260.                     break;
  2261.               case U_ESC: break;
  2262.               }
  2263.               break;
  2264.         case 'c': if (safe_mode) break;
  2265.               if (number_of_files)
  2266.               switch (copy_file(filenumber))
  2267.               {
  2268.              case FAILURE: show_error("Cannot copy this file");
  2269.                        repaint=TRUE;
  2270.                        extract_directory( searchstring );
  2271.                        if (filenumber > number_of_files)
  2272.                        {
  2273.                      filenumber=1;
  2274.                      current_page=0;
  2275.                        }
  2276.                        break;
  2277.              case SUCCESS: repaint=TRUE;
  2278.                        extract_directory( searchstring );
  2279.                        if (filenumber > number_of_files)
  2280.                        {
  2281.                      filenumber=1;
  2282.                      current_page=0;
  2283.                        }
  2284.                        break;
  2285.              case NOCHANGE: break;
  2286.               }
  2287.               break;
  2288.         case SCAN_A: find_first('A',¤t_page, &filenumber);
  2289.              break;
  2290.         case SCAN_B: find_first('B',¤t_page, &filenumber);
  2291.              break;
  2292.         case SCAN_C: find_first('C',¤t_page, &filenumber);
  2293.              break;
  2294.         case SCAN_D: find_first('D',¤t_page, &filenumber);
  2295.              break;
  2296.         case SCAN_E: find_first('E',¤t_page, &filenumber);
  2297.              break;
  2298.         case SCAN_F: find_first('F',¤t_page, &filenumber);
  2299.              break;
  2300.         case SCAN_G: find_first('G',¤t_page, &filenumber);
  2301.              break;
  2302.         case SCAN_H: find_first('H',¤t_page, &filenumber);
  2303.              break;
  2304.         case SCAN_I: find_first('I',¤t_page, &filenumber);
  2305.              break;
  2306.         case SCAN_J: find_first('J',¤t_page, &filenumber);
  2307.              break;
  2308.         case SCAN_K: find_first('K',¤t_page, &filenumber);
  2309.              break;
  2310.         case SCAN_L: find_first('L',¤t_page, &filenumber);
  2311.              break;
  2312.         case SCAN_M: find_first('M',¤t_page, &filenumber);
  2313.              break;
  2314.         case SCAN_N: find_first('N',¤t_page, &filenumber);
  2315.              break;
  2316.         case SCAN_O: find_first('O',¤t_page, &filenumber);
  2317.              break;
  2318.         case SCAN_P: find_first('P',¤t_page, &filenumber);
  2319.              break;
  2320.         case SCAN_Q: find_first('Q',¤t_page, &filenumber);
  2321.              break;
  2322.         case SCAN_R: find_first('R',¤t_page, &filenumber);
  2323.              break;
  2324.         case SCAN_S: find_first('S',¤t_page, &filenumber);
  2325.              break;
  2326.         case SCAN_T: find_first('T',¤t_page, &filenumber);
  2327.              break;
  2328.         case SCAN_U: find_first('U',¤t_page, &filenumber);
  2329.              break;
  2330.         case SCAN_V: find_first('V',¤t_page, &filenumber);
  2331.              break;
  2332.         case SCAN_W: find_first('W',¤t_page, &filenumber);
  2333.              break;
  2334.         case SCAN_X: find_first('X',¤t_page, &filenumber);
  2335.              break;
  2336.         case SCAN_Y: find_first('Y',¤t_page, &filenumber);
  2337.              break;
  2338.         case SCAN_Z: find_first('Z',¤t_page, &filenumber);
  2339.              break;
  2340.  
  2341.         case '!': sprintf(scratch,"Debug: near heap memory free: %u", _memmax()); /* debug info */
  2342.               show_message( scratch );
  2343.               break;
  2344.         case '@': sprintf(scratch,"Compiled on: %s, %s", __DATE__,__TIME__); /* debug info */
  2345.               show_message( scratch );
  2346.               break;
  2347.         default: break;
  2348.     } /* switch */
  2349.        } /* kbhit */
  2350.     } while (!finished);
  2351.  
  2352.     if (key!=ESC || finished)   /* do not miss the mouse selection */
  2353.     {
  2354.     /* construct filename */
  2355.     working(TRUE);
  2356.     lastdrive = _getdrive();
  2357.     working(FALSE);
  2358.     getpath( lastdrive, selected, _MAX_PATH );
  2359.     if (selected[strlen(selected)-1]!='\\') strcat(selected,"\\");
  2360.  
  2361.     strcat(selected,find[filenumber].name);
  2362.     }
  2363.  
  2364.     if (!exit_and_keep)         /* restore old situation */
  2365.     {
  2366.        _chdrive( olddrive );
  2367.        chdir( oldcwd );
  2368.     }
  2369.     hide_mouse();
  2370.     default_mouse_rectangle();
  2371.     /* Restore original foreground and background. */
  2372.     _settextcolor( oldfgd );
  2373.     _setbkcolor( oldbgd );
  2374.     _clearscreen( _GWINDOW );
  2375.     _settextwindow( 1, 1, 25, 80 );
  2376.     _settextposition( oldpos.row, oldpos.col );
  2377.     _settextcursor( oldcursor );
  2378.     if (find)
  2379.     {
  2380.        if (huge_find) _hfree( find );
  2381.        else
  2382.        {
  2383.      nearfind=(void __near *) ( ((long) find) & 0x0000FFFF);  /* 16 bits needed */
  2384.  
  2385.      _nfree( (FIND_T_SMALL __near *) nearfind );
  2386.        }
  2387.     }
  2388.     if (key==ESC && !finished)
  2389.     {
  2390.     if (exit_and_keep) return EXIT_KEEP;
  2391.     else return EXIT_RESTORE;
  2392.     }
  2393.     else return SUCCESS;
  2394. } /* end handle_dir */
  2395.  
  2396. /****************************************************************************
  2397.  renames file
  2398. */
  2399. int rename_file( int filenumber)
  2400. {
  2401.     char newname[50];
  2402.     int result;
  2403.     
  2404.     strcpy(newname,find[filenumber].name);
  2405.     if (edit("Rename: Enter a new filename, ESC to cancel",newname,48," +=[];|,<>/?*\"",ILLEGAL))
  2406.     {
  2407.     if (!strlen(newname)) return NOCHANGE;         /* null filename */
  2408.     if (!valid_filename(newname)) return FAILURE;  /* invalid filename */
  2409.     if (strcmp(find[filenumber].name,newname))
  2410.     { 
  2411.        working(TRUE);
  2412.        dos_error_auto_fail=TRUE;  
  2413.        result=rename(find[filenumber].name,newname);
  2414.        dos_error_auto_fail=FALSE;   
  2415.        working(FALSE);
  2416.        if (result) return FAILURE;
  2417.        else return SUCCESS;                        /* rename succeeded */
  2418.     }
  2419.     }
  2420.     return NOCHANGE;                                   /* ESCaped */
  2421. }
  2422.  
  2423. /****************************************************************************
  2424.  renames volume_label
  2425. */
  2426. int rename_volume_label( int filenumber)
  2427. {
  2428.     char newname[50];
  2429.     char *p;
  2430.     int result;
  2431.     
  2432.     strcpy(newname,find[filenumber].name);
  2433.     if (p=strrchr(newname,'.')) memmove( p, p+1, strlen(p+1)+1); /* remove . */
  2434.  
  2435.  
  2436.     if (edit("Enter a new volume label, ESC to cancel",newname,11,"+=[];|,.<>/?*\\:()&^\"",ILLEGAL))
  2437.     {
  2438.     if (!strlen(newname)) return NOCHANGE;         /* null filename */
  2439.     strupr(newname);
  2440.     if (strcmp(find[filenumber].name,newname))
  2441.     {    
  2442.        working(TRUE);
  2443.        result=FilSetVolid( (unsigned char) _getdrive() ,newname);
  2444.        working(FALSE);
  2445.        if (result!=NOERROR) return FAILURE;
  2446.        else return SUCCESS;
  2447.     }                           /* rename succeeded */
  2448.     }
  2449.     return NOCHANGE;                                   /* ESCaped */
  2450. }
  2451.  
  2452. /*************************************************************************
  2453.  Change file attributes
  2454. */
  2455. int ed_attributes( int filenumber)
  2456. {
  2457.     char attrbuf[5];
  2458.     unsigned int fattr;
  2459.     unsigned result;
  2460.     
  2461.     strcpy( attrbuf, "");
  2462.     if (find[filenumber].attrib & _A_RDONLY) strcat(attrbuf,"R");
  2463.     if (find[filenumber].attrib & _A_HIDDEN) strcat(attrbuf,"H");
  2464.     if (find[filenumber].attrib & _A_SYSTEM) strcat(attrbuf,"S");
  2465.     if (find[filenumber].attrib & _A_ARCH)   strcat(attrbuf,"A");
  2466.  
  2467.     if (edit("(R)eadonly, (H)idden, (S)ystem, (A)rchive",attrbuf,4,
  2468.     "RHSArhsa",LEGAL))
  2469.     {
  2470.       fattr=0;
  2471.       strlwr(attrbuf);
  2472.       if (strchr(attrbuf, 'r')) fattr|=_A_RDONLY;
  2473.       if (strchr(attrbuf, 'h')) fattr|=_A_HIDDEN;
  2474.       if (strchr(attrbuf, 's')) fattr|=_A_SYSTEM;
  2475.       if (strchr(attrbuf, 'a')) fattr|=_A_ARCH;
  2476.       if ((find[filenumber].attrib & (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH)) != (char) fattr)
  2477.       {
  2478.     working(TRUE);
  2479.     dos_error_auto_fail=TRUE;  
  2480.     result=_dos_setfileattr( find[filenumber].name, fattr) ;
  2481.     dos_error_auto_fail=FALSE;      
  2482.     working(FALSE);
  2483.     if (result) return FAILURE;
  2484.     else return SUCCESS;
  2485.       }
  2486.     }
  2487.     return NOCHANGE;
  2488. }
  2489.  
  2490.  
  2491. /*************************************************************************
  2492.  Change file date and time
  2493. */
  2494. int ed_datetime( int filenumber)
  2495. {
  2496.     unsigned result;
  2497.     char datetime[22];
  2498.     struct find_t pfind;
  2499.     int fh;
  2500.     unsigned int new_date;
  2501.     unsigned int new_time;
  2502.    
  2503.     /* get full file information */
  2504.     working(TRUE);
  2505.     dos_error_auto_fail=TRUE;
  2506.     if (!strcmp(find[filenumber].name,"..")) result=_dos_findfirst( ".", 0xffff, &pfind );
  2507.     else result=_dos_findfirst( find[filenumber].name, 0xffff, &pfind );
  2508.     working(FALSE);
  2509.     dos_error_auto_fail=FALSE;
  2510.     if (result) return FAILURE; /* not succeeded, get out */
  2511.       
  2512.     datestr( pfind.wr_date, datetime );
  2513.     strcat(datetime," ");
  2514.     timestr( pfind.wr_time, datetime+strlen(datetime) );
  2515.  
  2516.     if (edit("Date and time as DD-MON-YYYY HH:MM:SS",datetime,21,
  2517.     "0123456789- ABCDEFGJLMNOPRSTUVYabcdefgjlmnoprstuvy:",LEGAL))
  2518.     {                
  2519.       if (strlen(datetime)==20)
  2520.       {
  2521.         datetime[11]='\0';        
  2522.         new_date=strdate( datetime );
  2523.         new_time=strtime( datetime+12 );
  2524.         if (pfind.wr_time==new_time && pfind.wr_date==new_date)
  2525.            return NOCHANGE;
  2526.            
  2527.     working(TRUE);
  2528.     dos_error_auto_fail=TRUE;
  2529.     
  2530.         /* Open file with _dos_open function */
  2531.         dos_error_auto_fail=TRUE;
  2532.         if( _dos_open( pfind.name, _O_RDONLY, &fh ) != 0 )
  2533.         {
  2534.         working(FALSE);
  2535.         dos_error_auto_fail=FALSE;
  2536.             return FAILURE; 
  2537.         }
  2538.         /* Modify file date and time */
  2539.         dos_error_auto_fail=TRUE;
  2540.         result=_dos_setftime( fh, new_date, new_time );
  2541.         
  2542.         /* close file */
  2543.         if (_dos_close( fh ) != 0)
  2544.         {
  2545.             dos_error_auto_fail=FALSE;
  2546.             working(FALSE);
  2547.             return FAILURE; 
  2548.         }
  2549.     dos_error_auto_fail=FALSE;      
  2550.     working(FALSE);
  2551.     if (result) return FAILURE;
  2552.     else return SUCCESS;
  2553.       } else return FAILURE;
  2554.     }
  2555.     return NOCHANGE;
  2556. }
  2557.  
  2558. /***************************************************************************
  2559.  Copy file
  2560. */
  2561. int copy_file( int filenumber)
  2562. {
  2563.     char newname[50];
  2564.     int result;
  2565.  
  2566.     strcpy(newname,find[filenumber].name);
  2567.     if (edit("Copy: Enter a new filename, ESC to cancel",newname,48," +=[];|,<>/?*\"",ILLEGAL))
  2568.     {
  2569.     if (!strlen(newname)) return NOCHANGE;
  2570.     if (!valid_filename(newname)) return FAILURE;
  2571.     if (strcmp(find[filenumber].name,newname))
  2572.     {  
  2573.        working(TRUE);
  2574.        result=copy(find[filenumber].name,newname);
  2575.        working(FALSE);
  2576.        if (result) return FAILURE;
  2577.        else return SUCCESS;
  2578.     }
  2579.  
  2580.     }
  2581.     return NOCHANGE;
  2582. }
  2583.  
  2584. /**************************************************************************
  2585.  mkdir
  2586. */
  2587. int make_directory( void )
  2588. {
  2589.     char newname[50];
  2590.     int result;
  2591.     
  2592.     strcpy(newname,"");
  2593.     if (edit("Create: Enter a new directory name, ESC to cancel",newname,48," +=[];|,<>/?*\"",ILLEGAL))
  2594.     {
  2595.     if (!strlen(newname)) return NOCHANGE;
  2596.     if (!valid_filename(newname)) return FAILURE;
  2597.     working(TRUE);
  2598.     dos_error_auto_fail=TRUE;
  2599.     result=mkdir(newname);
  2600.     dos_error_auto_fail=FALSE;
  2601.     working(FALSE);
  2602.     if (result) return FAILURE;
  2603.        else return SUCCESS;
  2604.     }
  2605.     return NOCHANGE;
  2606. }
  2607.  
  2608.  
  2609.  
  2610. /***************************************************************************
  2611.  Displays common edit screen
  2612.  Returns FALSE if ESCaped
  2613. */
  2614. int edit(char *title, char *string, int length, char *legal_illegal, int legalmode)
  2615. {
  2616.     char scratch[_MAX_PATH];
  2617.     char b[(5*53)+10]={                /* Buffer for string */
  2618.                "╔══════════════════════════════════════════════════╗\n"
  2619.                "║                                                  ║\n"
  2620.                "╠══════════════════════════════════════════════════╣\n"
  2621.                "║                                                  ║\n"
  2622.                "╚══════════════════════════════════════════════════╝\n"
  2623.               };
  2624.     int result;
  2625.     char __near *savedscreen;
  2626.  
  2627.     strcpy(scratch,string);
  2628.  
  2629.     savedscreen=saveScrn();
  2630.  
  2631.     _settextcolor( (short) info_text_color );
  2632.     _setbkcolor( (long) info_bg_color );
  2633.  
  2634.     paint_box( b, 52, 5);
  2635.  
  2636.     _settextposition( 2, 3 );
  2637.     outtextm(title);
  2638.     if (editstring(4, 3, scratch, legal_illegal, legalmode, length))
  2639.     {
  2640.        strcpy(string,scratch);
  2641.        result=TRUE;
  2642.     }
  2643.     else result=FALSE;
  2644.  
  2645.     _settextwindow( 3, 1, 23, 80 );
  2646.     _setbkcolor( (long) screen_bg_color );
  2647.     savedscreen=restScrn(savedscreen);
  2648.     return result;
  2649. }
  2650.  
  2651.  
  2652. /***************************************************************************
  2653.  Returns ASCII or scancode + 256 if no ASCII
  2654. */
  2655. int getkey(void)
  2656. {
  2657.     int kread = _KEYBRD_READ;
  2658.     int kready = _KEYBRD_READY;
  2659.     int kshiftstatus = _KEYBRD_SHIFTSTATUS;
  2660.     unsigned key;
  2661.     int lo, hi;
  2662.     /* If bit 4 of the byte at 0x0040:0x0096 is set, the new keyboard
  2663.      * is present.
  2664.      */
  2665.     if( peek( 0x00400096 ) & 0x10 )
  2666.     {
  2667.     kread = _NKEYBRD_READ;
  2668.     kready = _NKEYBRD_READY;
  2669.     kshiftstatus = _NKEYBRD_SHIFTSTATUS;
  2670.     }
  2671.     key=_bios_keybrd( kread );
  2672.     lo = key & 0X00FF;
  2673.     hi = (key & 0XFF00) >> 8;
  2674.     return((lo == 0 || lo == 0xE0 ) ? hi + 256 : lo);
  2675. }
  2676.  
  2677. /****************************************************************************
  2678.  Changes the text cursor shape based on the current insert mode
  2679. */
  2680. void changecursor(int insmode)
  2681. {
  2682.  if (insmode)
  2683.   setcursor( 0x090C);
  2684.  else setcursor(0x0A0C);
  2685. } /* changecursor */
  2686.  
  2687. /***************************************************************************
  2688.  Sets the shape of the text cursor
  2689. */
  2690. void setcursor(unsigned int shape)
  2691. {
  2692.  union REGS reg;
  2693.  
  2694.  reg.h.ah = 1;
  2695.  reg.x.cx = shape;
  2696.  int86(0X10, ®, ®);
  2697. } /* setcursor */
  2698.   
  2699. unsigned int getshift(void)
  2700. {
  2701.     int kshiftstatus = _KEYBRD_SHIFTSTATUS;
  2702.  
  2703.     /* If bit 4 of the byte at 0x0040:0x0096 is set, the new keyboard
  2704.      * is present.
  2705.      */
  2706.     if( peek( 0x00400096 ) & 0x10 )
  2707.     {
  2708.         kshiftstatus = _NKEYBRD_SHIFTSTATUS;
  2709.     }
  2710.  
  2711.     /* Get shift state. */
  2712.     return (_bios_keybrd( kshiftstatus ));
  2713. }
  2714.  
  2715.   
  2716. /****************************************************************************
  2717.  Allows the user to edit a string with only certain characters allowed -
  2718.  Returns TRUE if ESC was not pressed, FALSE is ESC was pressed.
  2719. */
  2720. int editstring(int row, int col, char *s, char *legal_illegal, int legalmode, int maxlength)
  2721. {
  2722.  int c, len = strlen(s), pos = len;
  2723.  static int insert=TRUE;
  2724.  register int tel;
  2725.  int mouse_row, mouse_col;
  2726.  int ulc_row, ulc_col, dummy;          /* upper left corner row and column of window */
  2727.  int update=TRUE;
  2728.  static char old_strings[5][55]={"","","","",""};
  2729.  static int last_old_string=0;
  2730.  unsigned int shift;
  2731.  
  2732.  /* use next old_strings buffer */
  2733.  if (last_old_string<4) last_old_string++;
  2734.  else last_old_string=0;
  2735.  
  2736.  changecursor(insert);
  2737.  _gettextwindow(&ulc_row,&ulc_col,&dummy,&dummy);  /* mouse coordinates are absolute! */
  2738.  
  2739.  do
  2740.  {
  2741.   if (update)
  2742.   {
  2743.      hide_mouse();
  2744.      _settextposition( row, col );
  2745.      _outtext(s);
  2746.      for (tel=len;tel<=maxlength;tel++) _outtext(" ");
  2747.      _settextposition( row, col + pos );
  2748.      show_mouse();
  2749.      update=FALSE;
  2750.   }
  2751.  
  2752.   if (mouse_present)
  2753.   {
  2754.      restrict_mouse_topline();
  2755.      if (read_left_button_queue(&mouse_row,&mouse_col))
  2756.      {
  2757.     if (((mouse_row-ulc_row+1)==row) &&
  2758.         ((mouse_col-ulc_col+1)<=(col+len)) &&
  2759.         ((mouse_col-ulc_col+1)>=col))
  2760.     {
  2761.        pos=(mouse_col-ulc_col+1)-col;
  2762.        update=TRUE;
  2763.     }  else alert();
  2764.       }
  2765.    }
  2766.  
  2767.   if (n_kbhit())
  2768.   {
  2769.   update=TRUE;
  2770.   switch(c = getkey())
  2771.   {
  2772.    case K_CUP:
  2773.     if (maxlength>53) break; /* buffers too small */
  2774.     strcpy(old_strings[last_old_string],s);
  2775.     if (last_old_string>0) last_old_string--;
  2776.     else last_old_string=4;
  2777.     strcpy(s,old_strings[last_old_string]);
  2778.     if (strlen(s)<=(size_t) maxlength)                        /* check length */
  2779.     {   
  2780.       if (strlen(legal_illegal))
  2781.       {
  2782.     for (tel=0;tel<(int) strlen(s);tel++)
  2783.         {
  2784.             if ((legalmode==ILLEGAL &&  strchr(legal_illegal,s[tel])) ||
  2785.             (legalmode==LEGAL   && !strchr(legal_illegal,s[tel]))
  2786.                )
  2787.     
  2788.         {
  2789.         strcpy(s,"");
  2790.         break;
  2791.         }
  2792.     }    
  2793.       }    
  2794.     } else strcpy(s,"");
  2795.  
  2796.     len = strlen(s);
  2797.     pos = len;
  2798.     break;
  2799.    case K_CDN:
  2800.     if (maxlength>53) break; /* buffers too small */
  2801.     strcpy(old_strings[last_old_string],s);
  2802.     if (last_old_string<4) last_old_string++;
  2803.     else last_old_string=0;
  2804.     strcpy(s,old_strings[last_old_string]);
  2805.     if (strlen(s)<=(size_t) maxlength)                        /* check length */
  2806.     {
  2807.       if (strlen(legal_illegal))
  2808.     for (tel=0;tel<(int) strlen(s);tel++)
  2809.             if ((legalmode==ILLEGAL &&  strchr(legal_illegal,s[tel])) ||
  2810.             (legalmode==LEGAL   && !strchr(legal_illegal,s[tel]))
  2811.                )
  2812.     {
  2813.         strcpy(s,"");
  2814.         break;
  2815.     }
  2816.     } else strcpy(s,"");
  2817.  
  2818.     len = strlen(s);
  2819.     pos = len;
  2820.     break; 
  2821.     
  2822.    case K_F1:
  2823.    case K_F2:
  2824.    case K_F3:
  2825.    case K_F4:
  2826.    case K_F5:
  2827.    case K_F6:
  2828.    case K_F7:
  2829.    case K_F8:
  2830.    case K_F9:
  2831.    case K_F10:
  2832.    case K_PGDN:
  2833.    case K_PGUP: break;
  2834.  
  2835.    case K_HOME:
  2836.     pos = 0;
  2837.     break;
  2838.    case K_END:
  2839.     pos = len;
  2840.     break;
  2841.    case K_INS:
  2842.     insert = !insert;
  2843.     changecursor(insert);
  2844.     break;
  2845.    case K_CLE:
  2846.     if (pos > 0)
  2847.      pos--;
  2848.     break;
  2849.    case K_CRI:
  2850.     if (pos < len)
  2851.      pos++;
  2852.     break;
  2853.    case BS :
  2854.     if (pos > 0)
  2855.     {
  2856.      memmove(&s[pos - 1], &s[pos], len - pos + 1);
  2857.      pos--;
  2858.      len--;
  2859.     }
  2860.     break;
  2861.    case K_DEL:
  2862.     shift=getshift();
  2863.     if ((shift & 1) || (shift & 2))  /* left or right shift is down */
  2864.     {
  2865.             /* save string to be deleted */
  2866.             if (maxlength<127) /* else buffers too small */
  2867.             {
  2868.                 strcpy(old_strings[last_old_string],s);
  2869.                 if (last_old_string<4) last_old_string++;
  2870.                 else last_old_string=0;
  2871.             }
  2872.             len=0;     /* delete string */
  2873.             pos=len;
  2874.     }
  2875.     else
  2876.     if (pos < len)
  2877.     {
  2878.      memmove( &s[pos], &s[pos + 1],len - pos);
  2879.      len--;
  2880.     }
  2881.     break;
  2882.    case CR :
  2883.     if (maxlength<=53) strcpy(old_strings[last_old_string],s);
  2884.     break;
  2885.    case ESC :
  2886.     len = 0;
  2887.     break;
  2888.    default :
  2889.      if (!strlen(legal_illegal) ||
  2890.        (
  2891.       (legalmode==ILLEGAL && !strchr(legal_illegal,c)) ||
  2892.       (legalmode==LEGAL   &&  strchr(legal_illegal,c))
  2893.      )
  2894.         )
  2895.      if (((c >= ' ') && (c <= '~')))
  2896.      {
  2897.       if (insert && len == maxlength) alert();
  2898.       if (insert && len < maxlength)
  2899.       {
  2900.        memmove(&s[pos + 1], &s[pos], len - pos + 1);
  2901.        len++;
  2902.        s[pos++] = (char) c;
  2903.       }
  2904.       if (!insert && pos < maxlength)
  2905.       {
  2906.      if ((pos >= len) && (len < maxlength)) len++;
  2907.      s[pos++] = (char) c;
  2908.       }
  2909.      }
  2910.     break;
  2911.   } /* switch */
  2912.   }
  2913.   s[len] = 0;
  2914.  }
  2915.  while ((c != CR) && (c != ESC));
  2916.  changecursor(FALSE);
  2917.  setcursor(0x2000);
  2918.  return(c != ESC);
  2919. } /* editstring */
  2920.  
  2921.  
  2922. void construct_search_path( char *linebuf )
  2923. {
  2924.    strcpy(linebuf,"");
  2925.    getpath( _getdrive(), linebuf, _MAX_PATH );
  2926.    if (strlen(linebuf))
  2927.       if (linebuf[strlen(linebuf)-1]!='\\') strcat(linebuf,"\\\0");
  2928.    strcat(linebuf,searchstring);
  2929. }
  2930.  
  2931. /****************************************************************************
  2932.  Display current drive and working directory
  2933. */
  2934. void show_path( void )    /* this HAS some impact, searches disk on each call */
  2935. {
  2936.    char linebuf[_MAX_PATH];
  2937.  
  2938.    construct_search_path(linebuf);
  2939.    strlwr(linebuf);
  2940.    if (strlen(linebuf) >= 54)
  2941.    {
  2942.     linebuf[53]='';
  2943.     linebuf[54]='\0';
  2944.    }
  2945.    strcat(linebuf," ");
  2946.    while (strlen(linebuf)<56) strcat(linebuf,"═");
  2947.    _settextposition( 1, 15 );
  2948.    _settextcolor( (short) file_color );
  2949.    _setbkcolor( (long) screen_bg_color );
  2950.    outtextm(linebuf);
  2951. }
  2952.  
  2953. /***************************************************************************
  2954.  Check a full filename on illegal characters, name length, extension
  2955.  length, drive letter
  2956. */
  2957. int valid_filename( char *newname)
  2958. {
  2959.     char linebuf[_MAX_PATH];
  2960.     char *chrpointer;
  2961.     char illegal[20]={"\" +=[];|,<>/?*\\"};
  2962.     int length;
  2963.     register int teller;
  2964.  
  2965.     strcpy(linebuf,newname);
  2966.  
  2967.     if (strchr(illegal, linebuf[strlen(linebuf)-1])) return FALSE; /* check last character */
  2968.  
  2969.     if (strchr(linebuf,':'))   /* check drive */
  2970.     {
  2971.     if ((strchr(linebuf, ':') - linebuf)!=1) return FALSE; /* check place of : */
  2972.     linebuf[0] = (char) tolower((int) linebuf[0]);
  2973.     if ((linebuf[0] < 'a') || (linebuf[0] > 'z')) return FALSE;
  2974.     strcpy(linebuf,linebuf+2);  /* remove drive */
  2975.     }
  2976.  
  2977.     chrpointer = strtok( linebuf, "\\" );       /* Find first token */
  2978.     while( chrpointer != NULL )
  2979.     {
  2980.  
  2981.       chrpointer = strchr(linebuf,'.'); /* check extension */
  2982.       if (chrpointer)
  2983.       {
  2984.     if ((length=strlen(chrpointer+1))>3) return FALSE;           /* check size */
  2985.     for (teller=0;teller<length;teller++)
  2986.       if (strchr(illegal, *(chrpointer + 1 + teller))) return FALSE; /* check each character */
  2987.     *chrpointer = '\0';                                          /* remove extension */
  2988.       }
  2989.  
  2990.       chrpointer = strrchr(linebuf,'\\');        /* check name */
  2991.       if (!chrpointer) chrpointer=linebuf; /* no slash, start with first character */
  2992.       if (chrpointer)
  2993.       {
  2994.     if ((length=strlen(chrpointer+1))>8) return FALSE;           /* check size */
  2995.     for (teller=0;teller<length;teller++)
  2996.       if (strchr(illegal, *(chrpointer + 1 + teller))) return FALSE; /* check each character */
  2997.     *chrpointer = '\0';                                          /* remove name */
  2998.       }
  2999.  
  3000.      chrpointer = strtok( NULL, "\\" ); /* Find next token */
  3001.      }
  3002.     return TRUE;
  3003. }
  3004.  
  3005. /***************************************************************************
  3006.  Build a string with disk space free on current drive
  3007. */
  3008. int freespace( char *linebuf )
  3009. {
  3010.    int lastdrive;
  3011.    char scratch[_MAX_PATH];
  3012.    register int tel;
  3013.    int tel2;
  3014.    long freebytes;
  3015.    
  3016.    dos_error=0;
  3017.    dos_retries=0;
  3018.    lastdrive = _getdrive();
  3019.    
  3020.    if (getdiskfree( lastdrive, &freebytes )==FAILURE) return FAILURE;
  3021.  
  3022.    sprintf( scratch,"%ld",freebytes);
  3023.    
  3024.    strrev( scratch );
  3025.    linebuf[0]='\0';
  3026.    tel2=0;
  3027.    for (tel=0;tel<(int) strlen(scratch);tel++)
  3028.    {
  3029.        if (tel && !(tel%3)) linebuf[tel2++]=',';   /* thousands separator */
  3030.        linebuf[tel2++]=scratch[tel];
  3031.    }
  3032.    if (linebuf[tel2-1]==',') linebuf[tel2-1]='\0'; /* blank trailing ',' */
  3033.       else linebuf[tel2]='\0';                     /* terminate string */
  3034.    strrev( linebuf );
  3035.    strcpy( scratch,linebuf );
  3036.    strcpy( linebuf," Disk space free: ");
  3037.    strcat( linebuf,scratch );
  3038.    strcat( linebuf," bytes" );
  3039.    return SUCCESS;
  3040. }
  3041.  
  3042. /***************************************************************************
  3043.  Get disk space free on drive
  3044. */
  3045. int getdiskfree( int newdrive, long *freebytes )
  3046. {
  3047.    struct diskfree_t drvinfo;
  3048.    int current_drive;
  3049.    
  3050.    current_drive = _getdrive();
  3051.  
  3052.    dos_error=0;
  3053.    dos_retries=0;
  3054.    if (!drvalid(newdrive-1)) return FAILURE;
  3055.  
  3056.    dos_error_auto_fail=TRUE; 
  3057.    _dos_getdiskfree( newdrive, &drvinfo ); /* try to access the disk */
  3058.    dos_error_auto_fail=FALSE;  
  3059.    
  3060.    if (current_drive!=newdrive) _chdrive(current_drive); /* change to old device */
  3061.    
  3062.    if (dos_error) return FAILURE;
  3063.  
  3064.    *freebytes = ( (long)drvinfo.avail_clusters *
  3065.                 drvinfo.sectors_per_cluster *
  3066.                 drvinfo.bytes_per_sector );
  3067.    return SUCCESS;
  3068. }
  3069.  
  3070.  
  3071. void working( int mode )
  3072. {
  3073.    _settextposition( 1, 1 );
  3074.    _setbkcolor( screen_bg_color );
  3075.    if (mode)
  3076.    {
  3077.        _settextcolor( (short) info_text_color );
  3078.        outtextm( "" );
  3079.    }
  3080.    else
  3081.    {
  3082.        _settextcolor( (short) file_color );
  3083.        outtextm( "╔" );
  3084.    }
  3085. }
  3086.  
  3087.  
  3088.  
  3089. /***************************************************************************
  3090.  * Put shading under and at the right side of a box, if in COLOR mode
  3091.  */
  3092. void shadebox( short r1, short c1, short r2, short c2 )
  3093. {
  3094.   struct videoconfig vc;
  3095.   short int row, col;
  3096.   _getvideoconfig( &vc );
  3097.   if (vc.mode== _TEXTMONO) return;               /* monochroom scherm, geen schaduw */
  3098.   hide_mouse();
  3099.   for (row=r1+1;row<=r2+1;row++)
  3100.   {
  3101.      shadechar(row,c2+1);
  3102.      shadechar(row,c2+2);
  3103.   }
  3104.   for (col=c1+1;col<=c2+1;col++) shadechar(r2+1,col);
  3105.   show_mouse();
  3106. }
  3107.  
  3108. /***************************************************************************
  3109.  * Direct video write, shade a character
  3110.  */
  3111. #define MAKELONG(a, b)  ((long)(((unsigned)a) \
  3112.                | ((unsigned long)((unsigned)b)) << 16))
  3113. #define COLORTEXT_BUFFER   0XB800
  3114.  
  3115. void shadechar( int row, int col )
  3116. /* row    : row of location 1 to 25                     */
  3117. /* col    : column of location 1 to 80                  */
  3118. /* attrib : standard character attribute                */
  3119. {
  3120.     unsigned int offset; /* Offset from the segment address of
  3121.                 the desired video page */
  3122.     char far *y;         /* Long Pointer to the position in memory
  3123.                 where we will put the character and
  3124.                 it's attribute (next byte) */
  3125.     int pageno;  /* page number to load character into (0 to 3) */
  3126.     char attrib; /* standard character attribute                */
  3127.  
  3128.     pageno=0;
  3129.     attrib=0x08; /* background=black, textcolor=dark grey       */
  3130.     row--;  /* coord 1,1 is 0,0 for the function logic */
  3131.     col--;
  3132.  
  3133.     if (row<0 || row >24) return;   /* clip to screen boundary */
  3134.     if (col<0 || col >79) return;
  3135.  
  3136.     /* Calc the in-page offset w/page number offset and segment address */
  3137.     offset = (unsigned int) ((row * 160 )+(col*2)+(pageno*4096));
  3138.  
  3139.     /*  Set the attribute byte. See a DOS programmers reference for
  3140.     more information on video attributes. */
  3141.     offset++;
  3142.     y = (char far *)MAKELONG( offset, COLORTEXT_BUFFER);
  3143.     *y = attrib;
  3144. }
  3145.  
  3146. /* set working drive and directory and return a pointer to the first
  3147.  * character of the filename
  3148.  */
  3149. char *set_working_drive_and_dir( char *full_filename )
  3150. {
  3151.     char scratch[_MAX_PATH];
  3152.     char *slash;
  3153.     strcpy(scratch,full_filename); /* make drive & dir default */
  3154.     strupr(scratch);
  3155.     if (slash=strrchr(scratch, (int) '\\')) *slash='\0'; /* remove filename */
  3156.        else if (slash=strrchr(scratch, (int) ':')) *slash='\0'; /* maybe in format A:FILE.EXT */
  3157.     if (strlen(scratch)==1) strcat(scratch,":");                       /* top directory ? */
  3158.     if (strlen(scratch)==2) strcat(scratch,"\\");              /* top directory ? */
  3159.     if (scratch[1]==':') _chdrive(scratch[0]-'A'+1);
  3160.     chdir(scratch);
  3161.     /* find filename */
  3162.     if (slash=strrchr(full_filename, (int) '\\')) return slash+1;  /* in format A:\FILE.EXT */
  3163.        else if (slash=strrchr(scratch, (int) ':')) return slash+1; /* maybe in format A:FILE.EXT */
  3164.     return 0L;
  3165. }
  3166.  
  3167. /**************************************************************************
  3168.  Change to parent directory and place cursor
  3169. */
  3170. void find_parent( int *current_page, int *filenumber, char *searchstring)
  3171. {
  3172.      register int counter;
  3173.      char linebuf[_MAX_PATH];
  3174.      char *p;
  3175.      
  3176.      getpath( _getdrive(), linebuf, _MAX_PATH );
  3177.      
  3178.      if (p=strrchr(linebuf,'\\'))
  3179.      {
  3180.     memmove( linebuf, p+1, strlen(p+1)+1);
  3181.      } else return;                         /* do nothing */
  3182.  
  3183.      if (!strlen(linebuf)) return; /* do nothing, already in root */
  3184.      dos_error_auto_fail=TRUE;
  3185.      chdir( ".." );
  3186.      dos_error_auto_fail=FALSE;
  3187.      extract_directory( searchstring );
  3188.      if (!number_of_files)
  3189.      {
  3190.      *current_page=0;
  3191.      *filenumber=1;
  3192.      }
  3193.      else
  3194.      {
  3195.      for (counter=1;counter<number_of_files;counter++)    /* should end at last file */
  3196.          if (!strcmp(find[counter].name,linebuf)) break;
  3197.      *filenumber=counter;
  3198.      *current_page=((counter%114) ? counter/114 : counter/114 - 1);
  3199.      }
  3200. }
  3201.  
  3202.  
  3203. /*
  3204. **  Customized routines from DRVALID.C - validate disk drives
  3205. **  Original Copyright 1988-1991 by Bob Stout as part of
  3206. **  the MicroFirm Function Library (MFL)
  3207. **
  3208. **  public domain.
  3209. */
  3210.  
  3211.  
  3212. /*
  3213. **  getdrv()
  3214. **
  3215. **  returns the current drive.
  3216. **
  3217. **  Arguments: None.
  3218. **
  3219. **  Returns:   Current drive (0 = A:, 1 = B:, etc.)
  3220. **
  3221. **  Side effects: none
  3222. */
  3223.  
  3224. int getdrv(void)
  3225. {
  3226.       union REGS regs;
  3227.  
  3228.       regs.h.ah = 0x19;
  3229.       intdos(®s, ®s);
  3230.       return (regs.h.al);
  3231. }
  3232.  
  3233. /*
  3234. **  chdrv()
  3235. **
  3236. **  changes drives.
  3237. **
  3238. **  Arguments: 1 - target drive (0 = A:, 1 = B:, etc.)
  3239. **
  3240. **  Returns: SUCCESS or ERROR
  3241. **
  3242. **  Side effects: none
  3243. */
  3244.  
  3245. int chdrv(int drive)
  3246. {
  3247.       union REGS regs;
  3248.  
  3249.       regs.h.ah = 0x0e;
  3250.       regs.h.dl = (char)drive;
  3251.       intdos(®s, ®s);
  3252.       if (drive != getdrv())
  3253.         return ERROR;
  3254.       else  return SUCCESS;
  3255. }
  3256.  
  3257. /*
  3258. **  drvalid()
  3259. **
  3260. **  Verifies whether a logical disk drive is available without
  3261. **  triggering the DOS critical error handler, and changes to this drive
  3262. **  if successful.
  3263. **
  3264. **  Arguments: 1 - target drive (0 = A;, 1 = B:, etc.)
  3265. **
  3266. **  Returns:   TRUE  - drive is valid
  3267. **             FALSE - drive is invalid
  3268. **
  3269. **  Side effects: none
  3270. */
  3271.  
  3272. int drvalid(int drive)
  3273. {
  3274.       int original, result;
  3275.  
  3276.       original = getdrv();
  3277.       result   = (SUCCESS == chdrv(drive));
  3278.       if (!result) chdrv(original);
  3279.       return result;
  3280. }
  3281.  
  3282. void ScrPutS (char *String, unsigned char Attr,
  3283.           unsigned char Row, unsigned char Col)
  3284. {
  3285.     register unsigned char A;
  3286.     unsigned char far *PtrVideoMode = (unsigned char far *) 0x00400049;
  3287.     unsigned char far *Video;
  3288.  
  3289.     A = Attr;
  3290.  
  3291.     FP_SEG (Video) = (*PtrVideoMode == 7) ? 0xb000 : 0xb800;
  3292.     FP_OFF (Video) = Row*160+Col*2;
  3293.  
  3294.     while (*String)
  3295.     {
  3296.     *Video++ = *String++;
  3297.     *Video++ = A;
  3298.     }
  3299. }
  3300.  
  3301. /* Ask for a drive */
  3302. /* In: key a..z pressed */
  3303. /* Out: drive number A=1, B=2 etc. or -1 if ESCaped */
  3304.  
  3305. int ask_drive_number( char *message)
  3306. {
  3307.     int key;
  3308.     char __near *savedscreen;
  3309.  
  3310.     do
  3311.     {
  3312.        savedscreen=show_string( message , info_bg_color,info_text_color);
  3313.        _settextposition( 1, 1 );        /* prevent scroll-up from dos error */
  3314.        key = getkey();
  3315.        if (key<256) key = tolower(key);
  3316.     } while (((key < 'a') || (key > 'z')) &&(key != ESC));
  3317.  
  3318.     restScrn(savedscreen);      /* remove string box */
  3319.  
  3320.     if (key!=ESC) return ( key - 'a' + 1);
  3321.     else return -1;
  3322. }
  3323.  
  3324. char *getpath( int drive, char *buffer, int maxlen )
  3325. {
  3326.    char *result;
  3327.    
  3328.    dos_error_auto_fail=TRUE;
  3329.    if (!(result=_getdcwd( drive, buffer, maxlen )))
  3330.    {
  3331.        show_error("Cannot get disk path");
  3332.        strcpy(buffer,"");
  3333.    }
  3334.    dos_error_auto_fail=FALSE;
  3335.    return (result);
  3336. }
  3337.  
  3338. /****************************************************************************
  3339.  save screen image , return pointer to allocated memory
  3340. */
  3341. char __near *saveScrn(void)
  3342. {
  3343.   char far *src;
  3344.   char __near *saveArea;
  3345.   struct videoconfig vc;
  3346.  
  3347.   saveArea = (char __near *) _nmalloc (4096);       /* alloceer ruimte */
  3348.   if (!saveArea)
  3349.   {
  3350.        show_error("Cannot allocate memory for screen save");
  3351.        return (char __near *) NULL;
  3352.   }
  3353.   _getvideoconfig( &vc );
  3354.   if (vc.mode== _TEXTMONO)
  3355.      src = (char far *) 0xB0000000;     /* monochroom scherm */
  3356.     else
  3357.      src = (char far *) 0xB8000000;     /* grafische text buffer */
  3358.   hide_mouse();
  3359.   _fmemmove( (char far *) saveArea, (char far *) src, 4096 );
  3360.   show_mouse();
  3361.   return (saveArea);                             /* return pointer !!!! */
  3362. }
  3363.  
  3364.  
  3365. /***************************************************************************
  3366.  restore screen if saveArea != NULL
  3367.  Return NULL pointer for update of saveArea to prevent multiple restores
  3368.  Memory is freed so else garbage would be restored if saveScrn and restScrn
  3369.  are not balanced
  3370. */
  3371. char __near *restScrn(char __near *saveArea)
  3372. {
  3373.   char far *dest;
  3374.   struct videoconfig vc;
  3375.  
  3376.   if (!saveArea) return (char *) 0L;
  3377.  
  3378.   _getvideoconfig( &vc );
  3379.   if (vc.mode== _TEXTMONO)
  3380.      dest = (char far *) 0xB0000000;
  3381.   else
  3382.      dest = (char far *) 0xB8000000;
  3383.   hide_mouse();
  3384.   _fmemmove( (char far *) dest , (char far *) saveArea, 4096 );
  3385.   show_mouse();
  3386.   _nfree (saveArea);
  3387.   return (char __near *) NULL;
  3388. }
  3389.  
  3390.  
  3391.  
  3392.  
  3393. /***************************************************************************
  3394.  Displays common message screen
  3395. */
  3396. char __near *show_string(char *string, int bg_color, int text_color)
  3397. {
  3398.     char b[(5*53)+10]={                /* Buffer for string */
  3399.                "╔══════════════════════════════════════════════════╗\n"
  3400.                "║                                                  ║\n"
  3401.                "║                                                  ║\n"
  3402.                "║                                                  ║\n"
  3403.                "╚══════════════════════════════════════════════════╝\n"
  3404.               };
  3405.     char __near *savedscreen;
  3406.  
  3407.     savedscreen=saveScrn();
  3408.  
  3409.     _settextcolor( (short) text_color );
  3410.     _setbkcolor( (long) bg_color );
  3411.  
  3412.     paint_box( b, 52, 5);
  3413.  
  3414.     if (strchr( string, (int) '\n')) _settextposition( 2, 3);
  3415.     else
  3416.     {
  3417.     /* max length 48 */
  3418.     if (strlen(string) > 48 ) string[47]='\0';
  3419.     _settextposition( 3, 3 + (48-strlen(string))/2 );
  3420.     }
  3421.     outtextm(string);
  3422.  
  3423.     _settextwindow( 3, 1, 23, 80 );
  3424.     _settextcolor( (short) file_color );
  3425.     _setbkcolor( (long) screen_bg_color );
  3426.  
  3427.     return (savedscreen);
  3428. }
  3429.  
  3430.  
  3431.  
  3432. /***************************************************************************
  3433.  Paint box string
  3434. */
  3435. void paint_box(char *string, int vis_width, int vis_height)
  3436. {
  3437.     short x,y;
  3438.  
  3439.     y = ((25 - vis_height) / 2) + 1;
  3440.     x =  (80 - vis_width) / 2;
  3441.  
  3442.     /* Use text window to place output in middle of screen. */
  3443.     _settextwindow( y, x, y + vis_height, x + vis_width );
  3444.     shadebox( y, x, y + vis_height - 1, x + vis_width - 1 );
  3445.     outtextm( string );
  3446. }
  3447.  
  3448.  
  3449.  
  3450. /* Change dynamically the mouse restricting rectangle
  3451.  */
  3452. void restrict_mouse_topline( void )
  3453. {
  3454.     union REGS in_regs, out_regs;
  3455.     int col, row, top, bottom;
  3456.     static int old_top=4;
  3457.  
  3458.     if (!mouse_present) return;
  3459.  
  3460.     /* first save mouse position */
  3461.     in_regs.x.ax = 3;
  3462.     int86(0x33, &in_regs, &out_regs);
  3463.     col = out_regs.x.cx / 8 + 1;
  3464.     row = out_regs.x.dx / 8 + 1;
  3465.  
  3466.     /* Change cursor vertical restriction */
  3467.     if (col>71) top = 3;
  3468.     else top = 4;
  3469.  
  3470.     if (top!=old_top)
  3471.     {
  3472.     old_top = top;
  3473.  
  3474.     /* re-position mouse if needed */
  3475.     if (col<=71 && row==3)
  3476.     {
  3477.         in_regs.x.cx = 8 * (col - 1);
  3478.         in_regs.x.dx = 8 * (++row - 1);
  3479.         in_regs.x.ax = 4;
  3480.         int86(0x33, &in_regs, &out_regs);
  3481.     }
  3482.  
  3483.     /* Restrict cursor vertically */
  3484.     bottom = 22;
  3485.     in_regs.x.cx = 8 * (top - 1);
  3486.     in_regs.x.dx = 8 * (bottom - 1);
  3487.     in_regs.x.ax = 8;
  3488.     int86(0x33, &in_regs, &out_regs);
  3489.  
  3490.     }
  3491. }
  3492.  
  3493.  
  3494.  
  3495. /* Set the default mouse restricting rectangle
  3496.  */
  3497. void default_mouse_rectangle( void )
  3498. {
  3499.     union REGS in_regs, out_regs;
  3500.     int top, bottom, left, right;
  3501.  
  3502.     if (!mouse_present) return;
  3503.  
  3504.     right = 80;  /* Restrict cursor horizontally */
  3505.     left = 1;
  3506.     in_regs.x.cx = 8 * (right - 1);
  3507.     in_regs.x.dx = 8 * (left - 1);
  3508.     in_regs.x.ax = 7;
  3509.     int86(0x33, &in_regs, &out_regs);
  3510.     top = 1;               /* Restrict cursor vertically */
  3511.     bottom = 24;
  3512.     in_regs.x.cx = 8 * (top - 1);
  3513.     in_regs.x.dx = 8 * (bottom - 1);
  3514.     in_regs.x.ax = 8;
  3515.     int86(0x33, &in_regs, &out_regs);
  3516. }
  3517.  
  3518.  
  3519.  
  3520. int date_interval_correct(unsigned long file_datetime, unsigned long turnover_datetime, int turnover_datetime_mode)
  3521. {   
  3522.     if (turnover_datetime_mode==ALL) return TRUE;
  3523.     if (file_datetime>=turnover_datetime) return (turnover_datetime_mode==SINCE) ? TRUE : FALSE;
  3524.     else return (turnover_datetime_mode==SINCE) ? FALSE : TRUE;
  3525. }
  3526.  
  3527.   
  3528. /*************************************************************************
  3529.  Edit the turnover date and time string 
  3530. */
  3531. int ed_turnover_datetime( void )
  3532. {
  3533.     char scratch_datetime[23];
  3534.                                   
  3535.     strcpy(scratch_datetime,turnover_datetime_string);
  3536.     
  3537.     if (edit("Date and time since DD-MON-YYYY HH:MM:SS",scratch_datetime,22,
  3538.     "0123456789- ABCDEFGJLMNOPRSTUVYabcdefgjlmnoprstuvy:><+",LEGAL))
  3539.     {
  3540.       /* save new user string */
  3541.       strupr(scratch_datetime);
  3542.       strcpy(turnover_datetime_string,scratch_datetime);
  3543.       return (set_turnover_datetime(scratch_datetime));
  3544.          
  3545.     } else return NOCHANGE;
  3546. }
  3547.  
  3548.  
  3549. /*************************************************************************
  3550.  Convert a date and time string to the globals turnover_datetime
  3551.  and turnover_datetime_mode
  3552. */
  3553. int set_turnover_datetime( char *datetime )
  3554. {
  3555.     char scratch_datetime[23];
  3556.                                   
  3557.     strcpy(scratch_datetime,datetime);
  3558.     
  3559.          
  3560.     if (!strlen(scratch_datetime)) /* no before/since wanted */
  3561.     {
  3562.           turnover_datetime_mode=ALL;
  3563.           return SUCCESS;
  3564.     }    
  3565.         
  3566.     if (scratch_datetime[0]=='<' || scratch_datetime[0]=='-') /* forced to BEFORE by user */  
  3567.     {
  3568.         turnover_datetime_mode=BEFORE;
  3569.         strcpy(scratch_datetime,scratch_datetime+1);
  3570.     } else if (datetime[0]=='>' || scratch_datetime[0]=='+')  /* forced to SINCE by user */
  3571.            {
  3572.                turnover_datetime_mode=SINCE;
  3573.                strcpy(scratch_datetime,scratch_datetime+1);
  3574.            } else turnover_datetime_mode=SINCE; /* default to SINCE */
  3575.             
  3576.     if (!strcmp(scratch_datetime,"T") || !strcmp(scratch_datetime,"TODAY"))
  3577.     {                  
  3578.         /* build midnight date and time */          
  3579.         make_today_string( scratch_datetime );
  3580.         turnover_datetime=make_dt(strdate(scratch_datetime),0);
  3581.         return SUCCESS;                   
  3582.     }            
  3583.     if (strlen(scratch_datetime)==20) /* process full date-time string */
  3584.     {            
  3585.         scratch_datetime[11]='\0';        
  3586.         turnover_datetime=make_dt(strdate(scratch_datetime),strtime(scratch_datetime+12));
  3587.         return SUCCESS;
  3588.     }
  3589.     if (strlen(scratch_datetime)==11) /* process date string, set time to midnight */
  3590.     {            
  3591.         turnover_datetime=make_dt(strdate(scratch_datetime),0);
  3592.         return SUCCESS;
  3593.     } 
  3594.       
  3595.     /* syntax error, show all dates */          
  3596.     turnover_datetime_mode=ALL;
  3597.     return FAILURE;
  3598. }
  3599.  
  3600.  
  3601. void make_today_string( char *daystring )
  3602. {
  3603.     time_t ltime;
  3604.     struct tm *today;
  3605.  
  3606.     time( <ime );
  3607.     /* Use time structure to build a customized time string. */
  3608.     today = localtime( <ime );
  3609.  
  3610.     /* Use strftime to build a customized time string. */
  3611.     strftime( daystring, 13,"%d-%b-%Y", today );
  3612.     strupr(daystring);
  3613. }
  3614.